]> granicus.if.org Git - esp-idf/commitdiff
Merge branch 'bugfix/spiram_malloc_reserve_internal_fragments' into 'master'
authorAngus Gratton <angus@espressif.com>
Thu, 16 Aug 2018 03:19:39 +0000 (11:19 +0800)
committerAngus Gratton <angus@espressif.com>
Thu, 16 Aug 2018 03:19:39 +0000 (11:19 +0800)
esp32: Allow SPIRAM_MALLOC_RESERVE_INTERNAL to span multiple regions of memory

See merge request idf/esp-idf!2891

293 files changed:
.gitignore
.gitlab-ci.yml
.gitmodules
README.md
components/app_update/esp_ota_ops.c
components/app_update/include/esp_ota_ops.h
components/aws_iot/aws-iot-device-sdk-embedded-C
components/bootloader_support/include/bootloader_common.h
components/bootloader_support/include/esp_image_format.h
components/bootloader_support/include_bootloader/bootloader_sha.h
components/bootloader_support/src/bootloader_common.c
components/bootloader_support/src/bootloader_init.c
components/bootloader_support/src/bootloader_sha.c
components/bootloader_support/src/bootloader_utility.c
components/bootloader_support/src/esp_image_format.c
components/bootloader_support/src/flash_encrypt.c
components/bootloader_support/test/test_verify_image.c
components/bt/Kconfig
components/bt/bluedroid/api/esp_gattc_api.c
components/bt/bluedroid/api/include/api/esp_gatts_api.h
components/bt/bluedroid/bta/gatt/bta_gattc_cache.c
components/bt/bluedroid/bta/gatt/include/bta_gattc_int.h
components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c
components/bt/bluedroid/bta/jv/bta_jv_act.c
components/bt/bluedroid/btc/core/btc_dm.c
components/bt/bluedroid/btc/core/btc_task.c
components/bt/bluedroid/btc/include/btc/btc_task.h
components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c
components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c
components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c
components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c
components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h
components/bt/bluedroid/common/include/common/bt_defs.h
components/bt/bluedroid/common/include/common/bt_target.h
components/bt/bluedroid/hci/hci_hal_h4.c
components/bt/bluedroid/hci/hci_layer.c
components/bt/bluedroid/osi/include/osi/fixed_queue.h
components/bt/bluedroid/osi/include/osi/thread.h
components/bt/bluedroid/stack/avct/avct_lcb.c
components/bt/bluedroid/stack/avdt/avdt_ccb.c
components/bt/bluedroid/stack/avdt/avdt_l2c.c
components/bt/bluedroid/stack/avdt/avdt_scb.c
components/bt/bluedroid/stack/btm/btm_ble.c
components/bt/bluedroid/stack/btm/btm_ble_gap.c
components/bt/bluedroid/stack/btm/btm_main.c
components/bt/bluedroid/stack/btm/btm_sco.c
components/bt/bluedroid/stack/btm/btm_sec.c
components/bt/bluedroid/stack/btm/include/btm_int.h
components/bt/bluedroid/stack/btu/btu_init.c
components/bt/bluedroid/stack/gap/gap_conn.c
components/bt/bluedroid/stack/gatt/gatt_db.c
components/bt/bluedroid/stack/gatt/gatt_main.c
components/bt/bluedroid/stack/gatt/gatt_sr.c
components/bt/bluedroid/stack/gatt/gatt_utils.c
components/bt/bluedroid/stack/l2cap/l2c_api.c
components/bt/bluedroid/stack/l2cap/l2c_fcr.c
components/bt/bluedroid/stack/l2cap/l2c_utils.c
components/bt/bluedroid/stack/rfcomm/port_utils.c
components/bt/bluedroid/stack/rfcomm/rfc_utils.c
components/bt/bluedroid/stack/smp/include/p_256_ecc_pp.h
components/bt/bluedroid/stack/smp/p_256_ecc_pp.c
components/bt/bluedroid/stack/smp/smp_act.c
components/bt/bt.c
components/bt/lib
components/bt/test/component.mk [new file with mode: 0644]
components/bt/test/test_smp.c [new file with mode: 0644]
components/driver/gpio.c
components/driver/include/driver/touch_pad.h
components/driver/rtc_module.c
components/driver/test/test_adc2.c
components/driver/test/test_spi_master.c
components/driver/test/test_uart.c
components/driver/uart.c
components/esp32/core_dump.c
components/esp32/cpu_start.c
components/esp32/esp_err_to_name.c
components/esp32/include/esp_mesh.h
components/esp32/include/esp_mesh_internal.h
components/esp32/include/esp_panic.h
components/esp32/include/esp_spiram.h
components/esp32/include/esp_wifi_internal.h
components/esp32/include/esp_wifi_types.h
components/esp32/include/rom/libc_stubs.h
components/esp32/ld/esp32.common.ld
components/esp32/lib
components/esp32/panic.c
components/esp32/sleep_modes.c
components/esp32/spiram.c
components/esp32/spiram_psram.c
components/esp32/spiram_psram.h
components/esp32/system_api.c
components/esp32/test/test_esp32.c
components/esp_http_client/esp_http_client.c
components/esp_http_client/include/esp_http_client.h
components/esp_http_client/lib/http_utils.c
components/esp_http_client/lib/transport_ssl.c
components/esp_https_ota/component.mk [new file with mode: 0644]
components/esp_https_ota/include/esp_https_ota.h [new file with mode: 0644]
components/esp_https_ota/src/esp_https_ota.c [new file with mode: 0644]
components/espcoredump/espcoredump.py
components/expat/COPYING [deleted file]
components/expat/README [deleted file]
components/expat/component.mk
components/expat/expat [new submodule]
components/expat/include/expat/ascii.h [deleted file]
components/expat/include/expat/asciitab.h [deleted file]
components/expat/include/expat/expat.h [deleted file]
components/expat/include/expat/expat_external.h [deleted file]
components/expat/include/expat/iasciitab.h [deleted file]
components/expat/include/expat/internal.h [deleted file]
components/expat/include/expat/latin1tab.h [deleted file]
components/expat/include/expat/nametab.h [deleted file]
components/expat/include/expat/utf8tab.h [deleted file]
components/expat/include/expat/xmlrole.h [deleted file]
components/expat/include/expat/xmltok.h [deleted file]
components/expat/include/expat/xmltok_impl.h [deleted file]
components/expat/library/xmlparse.c [deleted file]
components/expat/library/xmlrole.c [deleted file]
components/expat/library/xmltok.c [deleted file]
components/expat/library/xmltok_impl.c [deleted file]
components/expat/library/xmltok_ns.c [deleted file]
components/expat/port/chardata.c [deleted file]
components/expat/port/expat_element.c [deleted file]
components/expat/port/include/chardata.h [deleted file]
components/expat/port/include/expat_config.h [moved from components/expat/include/expat/expat_config.h with 91% similarity]
components/expat/port/include/minicheck.h [deleted file]
components/expat/port/minicheck.c [deleted file]
components/expat/test/component.mk [new file with mode: 0644]
components/expat/test/test_expat.c [new file with mode: 0644]
components/fatfs/src/diskio_wl.c
components/fatfs/src/diskio_wl.h
components/fatfs/src/vfs_fat_spiflash.c
components/fatfs/test/test_fatfs_sdmmc.c
components/freertos/portmux_impl.inc.h
components/heap/heap_caps.c
components/heap/heap_caps_init.c
components/heap/include/esp_heap_trace.h
components/idf_test/integration_test/TC_IT_TCPIP_DHCP.yml
components/idf_test/integration_test/TC_IT_WIFI_CONN.yml
components/mbedtls/Kconfig
components/mbedtls/mbedtls
components/mbedtls/port/include/mbedtls/esp_config.h
components/mdns/mdns.c
components/newlib/platform_include/sys/random.h [new file with mode: 0644]
components/newlib/random.c [new file with mode: 0644]
components/newlib/syscalls.c
components/nvs_flash/include/nvs.h
components/nvs_flash/src/nvs_page.cpp
components/nvs_flash/src/nvs_page.hpp
components/nvs_flash/src/nvs_storage.cpp
components/nvs_flash/test/test_nvs.c
components/nvs_flash/test_nvs_host/test_nvs.cpp
components/partition_table/Kconfig.projbuild
components/partition_table/gen_esp32part.py
components/partition_table/partitions_singleapp.csv
components/partition_table/partitions_singleapp_coredump.csv
components/partition_table/partitions_two_ota.csv
components/partition_table/partitions_two_ota_coredump.csv
components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py
components/soc/component.mk
components/soc/esp32/include/soc/soc.h
components/soc/esp32/rtc_wdt.c [new file with mode: 0644]
components/soc/esp32/soc_memory_layout.c
components/soc/include/soc/rtc_wdt.h [new file with mode: 0644]
components/soc/include/soc/soc_memory_layout.h
components/soc/src/memory_layout_utils.c [new file with mode: 0644]
components/spi_flash/flash_mmap.c
components/spi_flash/include/esp_partition.h
components/spi_flash/include/esp_spi_flash.h
components/spi_flash/partition.c
components/spi_flash/sim/stubs/Makefile.files
components/spi_flash/sim/stubs/bootloader_support/include/bootloader_common.h [new file with mode: 0644]
components/spi_flash/sim/stubs/bootloader_support/src/bootloader_common.c [new file with mode: 0644]
components/spi_flash/sim/stubs/esp32/esp_random.c [new file with mode: 0644]
components/spi_flash/sim/stubs/esp32/include/esp_system.h [new file with mode: 0644]
components/spi_flash/sim/stubs/log/include/esp_log.h
components/ulp/component_ulp_common.mk
components/ulp/include/esp32/ulp.h
components/ulp/test/component.mk
components/ulp/test/test_ulp_as.c [new file with mode: 0644]
components/ulp/test/ulp/test_jumps.S [new file with mode: 0644]
components/wear_levelling/WL_Flash.cpp
components/wear_levelling/doc/wl_sw_structure.rst
components/wear_levelling/private_include/WL_Flash.h
components/wear_levelling/private_include/WL_State.h
components/wear_levelling/test/component.mk
components/wear_levelling/test/test_partition_v1.bin [new file with mode: 0644]
components/wear_levelling/test/test_wl.c
components/wear_levelling/test_wl_host/Makefile
components/wear_levelling/wear_levelling.cpp
components/wpa_supplicant/component.mk
docs/Doxyfile
docs/_static/espressif-logo.svg [new file with mode: 0644]
docs/_static/theme_overrides.css
docs/conf_common.py
docs/docs_common.mk [new file with mode: 0644]
docs/en/COPYRIGHT.rst
docs/en/Makefile
docs/en/api-guides/core_dump.rst
docs/en/api-guides/partition-tables.rst
docs/en/api-guides/ulp.rst
docs/en/api-guides/ulp_instruction_set.rst
docs/en/api-guides/wifi.rst
docs/en/api-reference/peripherals/adc.rst
docs/en/api-reference/system/esp_https_ota.rst [new file with mode: 0644]
docs/en/api-reference/system/heap_debug.rst
docs/en/api-reference/system/index.rst
docs/en/api-reference/system/ota.rst
docs/en/get-started/establish-serial-connection.rst
docs/en/get-started/index.rst
docs/en/hw-reference/modules-and-boards-previous.rst
docs/en/hw-reference/modules-and-boards.rst
docs/en/index.rst
docs/en/security/flash-encryption.rst
docs/en/versions.rst [new file with mode: 0644]
docs/gen-version-specific-includes.py [new file with mode: 0755]
docs/zh_CN/Makefile
docs/zh_CN/api-guides/unit-tests.rst
docs/zh_CN/api-reference/system/esp_https_ota.rst [new file with mode: 0644]
docs/zh_CN/get-started/index.rst
docs/zh_CN/index.rst
docs/zh_CN/versions.rst [new file with mode: 0644]
examples/bluetooth/a2dp_gatts_coex/main/main.c
examples/bluetooth/a2dp_sink/main/main.c
examples/bluetooth/a2dp_source/main/main.c
examples/bluetooth/ble_adv/main/app_bt.c
examples/bluetooth/ble_hid_device_demo/main/ble_hidd_demo_main.c
examples/bluetooth/ble_hid_device_demo/main/hid_device_le_prf.c
examples/bluetooth/ble_spp_server/main/ble_spp_server_demo.c
examples/bluetooth/ble_throughput/throughput_client/main/example_ble_client_throughput.c
examples/bluetooth/ble_throughput/throughput_server/main/example_ble_server_throughput.c
examples/bluetooth/blufi/main/blufi_example_main.c
examples/bluetooth/bt_discovery/main/bt_discovery.c
examples/bluetooth/bt_spp_acceptor/main/example_spp_acceptor_demo.c
examples/bluetooth/bt_spp_initiator/main/example_spp_initiator_demo.c
examples/bluetooth/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c
examples/bluetooth/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c
examples/bluetooth/controller_hci_uart/main/controller_hci_uart_demo.c
examples/bluetooth/gatt_client/main/gattc_demo.c
examples/bluetooth/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md
examples/bluetooth/gatt_security_client/main/example_ble_sec_gattc_demo.c
examples/bluetooth/gatt_security_server/main/example_ble_sec_gatts_demo.c
examples/bluetooth/gatt_server/main/gatts_demo.c
examples/bluetooth/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md
examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c
examples/bluetooth/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md
examples/bluetooth/gattc_multi_connect/main/gattc_multi_connect.c
examples/protocols/asio/chat_client/asio_chat_client_test.py
examples/protocols/asio/chat_server/asio_chat_server_test.py
examples/protocols/asio/tcp_echo_server/asio_tcp_server_test.py
examples/protocols/asio/udp_echo_server/asio_udp_server_test.py
examples/protocols/aws_iot/subscribe_publish/main/subscribe_publish_sample.c
examples/protocols/aws_iot/thing_shadow/main/thing_shadow_sample.c
examples/protocols/esp_http_client/esp_http_client_test.py
examples/protocols/esp_http_client/main/esp_http_client_example.c
examples/protocols/http2_request/main/http2_request_example_main.c
examples/storage/nvs_rw_blob/main/nvs_blob_example_main.c
examples/storage/nvs_rw_value/main/nvs_value_example_main.c
examples/system/console/main/console_example_main.c
examples/system/ota/README.md
examples/system/ota/native_ota_example/Makefile [moved from examples/system/ota/Makefile with 85% similarity]
examples/system/ota/native_ota_example/README.md [new file with mode: 0644]
examples/system/ota/native_ota_example/main/Kconfig.projbuild [moved from examples/system/ota/main/Kconfig.projbuild with 52% similarity]
examples/system/ota/native_ota_example/main/component.mk [moved from examples/system/ota/main/component.mk with 62% similarity]
examples/system/ota/native_ota_example/main/native_ota_example.c [moved from examples/system/ota/main/ota_example_main.c with 51% similarity]
examples/system/ota/native_ota_example/sdkconfig.defaults [moved from examples/system/ota/sdkconfig.defaults with 100% similarity]
examples/system/ota/server_certs/ca_cert.pem [new file with mode: 0644]
examples/system/ota/simple_ota_example/Makefile [new file with mode: 0644]
examples/system/ota/simple_ota_example/README.md [new file with mode: 0644]
examples/system/ota/simple_ota_example/main/Kconfig.projbuild [new file with mode: 0644]
examples/system/ota/simple_ota_example/main/component.mk [new file with mode: 0644]
examples/system/ota/simple_ota_example/main/simple_ota_example.c [new file with mode: 0644]
examples/system/ota/simple_ota_example/sdkconfig.defaults [new file with mode: 0644]
examples/system/ulp/main/ulp_example_main.c
examples/system/ulp_adc/main/ulp_adc_example_main.c
examples/wifi/espnow/main/espnow_example_main.c
examples/wifi/iperf/main/main.c
examples/wifi/power_save/main/power_save.c
examples/wifi/scan/main/scan.c
examples/wifi/simple_wifi/main/simple_wifi.c
examples/wifi/wps/main/wps.c
tools/ci/executable-list.txt
tools/ci/mirror-list.txt
tools/tiny-test-fw/DUT.py
tools/unit-test-app/README.md
tools/unit-test-app/components/unity/unity_platform.c
tools/unit-test-app/configs/bt [new file with mode: 0644]
tools/unit-test-app/configs/default
tools/unit-test-app/configs/libsodium
tools/unit-test-app/configs/psram
tools/unit-test-app/configs/release
tools/unit-test-app/configs/single_core
tools/unit-test-app/unit_test.py [changed mode: 0644->0755]

index 24639f73f91e7d07cdc805a0d14678d6639b2de8..84039cf1440c014f0f0e4fcc5e1fc3ad4a9ba981 100644 (file)
@@ -46,6 +46,8 @@ tools/unit-test-app/output
 # IDF monitor test
 tools/test_idf_monitor/outputs
 
+TEST_LOGS
+
 # AWS IoT Examples require device-specific certs/keys
 examples/protocols/aws_iot/*/main/certs/*.pem.*
 
index 49d48dd9fe4db4a0225ac033e8ca074a433cc810..7818a02f93523a418f989852d369dee67b6c8b00 100644 (file)
@@ -305,7 +305,7 @@ test_fatfs_on_host:
 
 test_mdns_fuzzer_on_host:
   stage: host_test
-  image: $CI_DOCKER_REGISTRY/afl-fuzzer-test$BOT_DOCKER_IMAGE_TAG
+  image: $CI_DOCKER_REGISTRY/afl-fuzzer-test
   tags:
     - host_test
   dependencies: []
@@ -390,7 +390,7 @@ push_to_github:
     - git remote add github git@github.com:espressif/esp-idf.git
     # Need separate push commands for tag builds and for branch builds
     - "[ -n \"${CI_COMMIT_TAG}\" ] && git push github ${CI_COMMIT_TAG}"
-    - "[ -z \"${CI_COMMIT_TAG}\" ] && git push github ${CI_COMMIT_SHA}:/refs/heads/${CI_COMMIT_REF_NAME}"
+    - "[ -z \"${CI_COMMIT_TAG}\" ] && git push github ${CI_COMMIT_SHA}:refs/heads/${CI_COMMIT_REF_NAME}"
 
 deploy_docs:
   stage: host_test
@@ -512,7 +512,7 @@ check_submodule_sync:
 assign_test:
   tags:
     - assign_test
-  image: $CI_DOCKER_REGISTRY/ubuntu-test-env$BOT_DOCKER_IMAGE_TAG
+  image: $CI_DOCKER_REGISTRY/ubuntu-test-env
   stage: assign_test
   # gitlab ci do not support match job with RegEx or wildcard now in dependencies.
   # we have a lot build example jobs. now we don't use dependencies, just download all artificats of build stage.
@@ -1117,6 +1117,12 @@ UT_010_04:
     - UT_T1_RMT
     - psram
 
+UT_601_01:
+  <<: *unit_test_template
+  tags:
+    - ESP32_IDF
+    - UT_T1_1
+
 IT_001_01:
   <<: *test_template
   tags:
index 5c800c562bdc19eeed520f47b4d49838be03d00c..2a9eaef01038c14614335f34fd1298dda9955011 100644 (file)
@@ -45,3 +45,7 @@
 [submodule "components/asio/asio"]
        path = components/asio/asio
        url = https://github.com/espressif/asio.git
+
+[submodule "components/expat/expat"]
+       path = components/expat/expat
+       url = https://github.com/libexpat/libexpat.git
index e2ed414ff472b6af116532971a17f8ebb9422636..42d8f45b4db1a2bdf69d1f9d78872252a65a7506 100644 (file)
--- a/README.md
+++ b/README.md
@@ -4,22 +4,27 @@
 
 ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview) chip.
 
-# Developing With the ESP-IDF
+# Developing With ESP-IDF
 
 ## Setting Up ESP-IDF
 
 See setup guides for detailed instructions to set up the ESP-IDF:
 
-* [Windows Setup Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/windows-setup.html)
-* [Mac OS Setup Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/macos-setup.html)
-* [Linux Setup Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/linux-setup.html)
+* [Getting Started Guide for the stable ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/)
+* [Getting Started Guide for the latest (master branch) ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/)
 
 ## Finding a Project
 
-As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in the setup guide, ESP-IDF comes with some example projects in the [examples](examples) directory.
+As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in Getting Started, ESP-IDF comes with some example projects in the [examples](examples) directory.
 
 Once you've found the project you want to work with, change to its directory and you can configure and build it.
 
+To start your own project based on an example, copy the example project directory outside of the ESP-IDF directory.
+
+# Quick Reference
+
+See the Getting Started guide links above for a detailed setup guide. This is a quick reference for common commands when working with ESP-IDF projects:
+
 ## Configuring the Project
 
 `make menuconfig`
@@ -36,15 +41,17 @@ Once done configuring, press Escape multiple times to exit and say "Yes" to save
 
 ## Compiling the Project
 
-`make all`
+`make -j4 all`
 
 ... will compile app, bootloader and generate a partition table based on the config.
 
+NOTE: The `-j4` option causes `make` to run 4 parallel jobs. This is much faster than the default single job. The recommended number to pass to this option is `-j(number of CPUs + 1)`.
+
 ## Flashing the Project
 
 When `make all` finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this from make by running:
 
-`make flash`
+`make -j4 flash`
 
 This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with `make menuconfig`.
 
@@ -56,24 +63,24 @@ The `make monitor` target uses the [idf_monitor tool](https://docs.espressif.com
 
 Exit the monitor by typing Ctrl-].
 
-To flash and monitor output in one pass, you can run:
+To build, flash and monitor output in one pass, you can run:
 
-`make flash monitor`
+`make -j4 flash monitor`
 
-## Compiling & Flashing Just the App
+## Compiling & Flashing Only the App
 
 After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table:
 
 * `make app` - build just the app.
 * `make app-flash` - flash just the app.
 
-`make app-flash` will automatically rebuild the app if it needs it.
+`make app-flash` will automatically rebuild the app if any source files have changed.
 
 (In normal development there's no downside to reflashing the bootloader and partition table each time, if they haven't changed.)
 
 ## Parallel Builds
 
-ESP-IDF supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to or one more than the number of CPU cores in your system.)
+ESP-IDF supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to the number of CPU cores in your system, plus one.)
 
 Multiple make functions can be combined into one. For example: to build the app & bootloader using 5 jobs in parallel, then flash everything, and then display serial output from the ESP32 run:
 
index 48542c23f66cf14ab706f898a421eaa4d42bb773..c7ac0bc6a2b1a5969faee0e63250f5583fa5f5ef 100644 (file)
@@ -235,7 +235,7 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
       .size = it->part->size,
     };
 
-    if (esp_image_load(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
+    if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
         ret = ESP_ERR_OTA_VALIDATE_FAILED;
         goto cleanup;
     }
@@ -372,7 +372,7 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition)
         .offset = partition->address,
         .size = partition->size,
     };
-    if (esp_image_load(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
+    if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
         return ESP_ERR_OTA_VALIDATE_FAILED;
     }
 
index a089a92be0519a6d3d8cdff68640e22bb4257848..291d6375e4ede988f9ed4540b6e7dcdefbe114e4 100644 (file)
@@ -133,7 +133,7 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t* partition);
  * If the OTA data partition is not present or not valid then the result is the first app partition found in the
  * partition table. In priority order, this means: the factory app, the first OTA app slot, or the test app partition.
  *
- * Note that there is no guarantee the returned partition is a valid app. Use esp_image_load(ESP_IMAGE_VERIFY, ...) to verify if the
+ * Note that there is no guarantee the returned partition is a valid app. Use esp_image_verify(ESP_IMAGE_VERIFY, ...) to verify if the
  * returned partition contains a bootable image.
  *
  * @return Pointer to info for partition structure, or NULL if partition table is invalid or a flash read operation failed. Any returned pointer is valid for the lifetime of the application.
index 8bf852db77c360eebfa4b800754fdb90e29ea43e..299183238ffe7a3e6a5ca0af9db19c10eaca62cf 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8bf852db77c360eebfa4b800754fdb90e29ea43e
+Subproject commit 299183238ffe7a3e6a5ca0af9db19c10eaca62cf
index 07fc9341c503e093504399bd4a2ad7705eee384b..d5a92cc79b6563068699b730b3c5810132a24bf4 100644 (file)
@@ -68,3 +68,26 @@ bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_dat
  * @return    Returns true if the list contains the label, false otherwise.
  */
 bool bootloader_common_label_search(const char *list, char *label);
+
+/**
+ * @brief Calculates a sha-256 for a given partition or returns a appended digest.
+ *
+ * This function can be used to return the SHA-256 digest of application, bootloader and data partitions.
+ * For apps with SHA-256 appended to the app image, the result is the appended SHA-256 value for the app image content.
+ * The hash is verified before returning, if app content is invalid then the function returns ESP_ERR_IMAGE_INVALID.
+ * For apps without SHA-256 appended to the image, the result is the SHA-256 of all bytes in the app image.
+ * For other partition types, the result is the SHA-256 of the entire partition.
+ *
+ * @param[in]  address      Address of partition.
+ * @param[in]  size         Size of partition.
+ * @param[in]  type         Type of partition. For applications the type is 0, otherwise type is data.
+ * @param[out] out_sha_256  Returned SHA-256 digest for a given partition.
+ *
+ * @return
+ *          - ESP_OK: In case of successful operation.
+ *          - ESP_ERR_INVALID_ARG: The size was 0 or the sha_256 was NULL.
+ *          - ESP_ERR_NO_MEM: Cannot allocate memory for sha256 operation.
+ *          - ESP_ERR_IMAGE_INVALID: App partition doesn't contain a valid app image.
+ *          - ESP_FAIL: An allocation error occurred.
+ */
+esp_err_t bootloader_common_get_sha256_of_partition(uint32_t address, uint32_t size, int type, uint8_t *out_sha_256);
index 6d332d810f3545a91d4f25b1095ebecdc1b7ceef..6d92a35b0061e7ee50423e8175e5e9661e6a52ea 100644 (file)
@@ -96,11 +96,12 @@ typedef struct {
   esp_image_segment_header_t segments[ESP_IMAGE_MAX_SEGMENTS]; /* Per-segment header data */
   uint32_t segment_data[ESP_IMAGE_MAX_SEGMENTS]; /* Data offsets for each segment */
   uint32_t image_len; /* Length of image on flash, in bytes */
+  uint8_t image_digest[32]; /* appended SHA-256 digest */
 } esp_image_metadata_t;
 
 /* Mode selection for esp_image_load() */
 typedef enum {
-    ESP_IMAGE_VERIFY,        /* Verify image contents, load metadata. Print errorsors. */
+    ESP_IMAGE_VERIFY,        /* Verify image contents, load metadata. Print errors. */
     ESP_IMAGE_VERIFY_SILENT, /* Verify image contents, load metadata. Don't print errors. */
 #ifdef BOOTLOADER_BUILD
     ESP_IMAGE_LOAD,          /* Verify image contents, load to memory. Print errors. */
@@ -110,6 +111,11 @@ typedef enum {
 /**
  * @brief Verify and (optionally, in bootloader mode) load an app image.
  *
+ * This name is deprecated and is included for compatibility with the ESP-IDF v3.x API.
+ * It will be removed in V4.0 version.
+ * Function has been renamed to esp_image_verify().
+ * Use function esp_image_verify() to verify a image. And use function bootloader_load_image() to load image from a bootloader space.
+ *
  * If encryption is enabled, data will be transparently decrypted.
  *
  * @param mode Mode of operation (verify, silent verify, or load).
@@ -130,7 +136,60 @@ typedef enum {
  * - ESP_ERR_IMAGE_INVALID if the image appears invalid.
  * - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid.
  */
-esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data);
+esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) __attribute__((deprecated));
+
+/**
+ * @brief Verify an app image.
+ *
+ * If encryption is enabled, data will be transparently decrypted.
+ *
+ * @param mode Mode of operation (verify, silent verify, or load).
+ * @param part Partition to load the app from.
+ * @param[inout] data Pointer to the image metadata structure which is be filled in by this function.
+ *                    'start_addr' member should be set (to the start address of the image.)
+ *                    Other fields will all be initialised by this function.
+ *
+ * Image validation checks:
+ * - Magic byte.
+ * - Partition smaller than 16MB.
+ * - All segments & image fit in partition.
+ * - 8 bit image checksum is valid.
+ * - SHA-256 of image is valid (if image has this appended).
+ * - (Signature) if signature verification is enabled.
+ *
+ * @return
+ * - ESP_OK if verify or load was successful
+ * - ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs
+ * - ESP_ERR_IMAGE_INVALID if the image appears invalid.
+ * - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid.
+ */
+esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data);
+
+/**
+ * @brief Verify and load an app image (available only in space of bootloader).
+ *
+ * If encryption is enabled, data will be transparently decrypted.
+ *
+ * @param part Partition to load the app from.
+ * @param[inout] data Pointer to the image metadata structure which is be filled in by this function.
+ *                    'start_addr' member should be set (to the start address of the image.)
+ *                    Other fields will all be initialised by this function.
+ *
+ * Image validation checks:
+ * - Magic byte.
+ * - Partition smaller than 16MB.
+ * - All segments & image fit in partition.
+ * - 8 bit image checksum is valid.
+ * - SHA-256 of image is valid (if image has this appended).
+ * - (Signature) if signature verification is enabled.
+ *
+ * @return
+ * - ESP_OK if verify or load was successful
+ * - ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs
+ * - ESP_ERR_IMAGE_INVALID if the image appears invalid.
+ * - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid.
+ */
+esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data);
 
 /**
  * @brief Verify the bootloader image.
index 38bd080485dccd21433959cd0254e94220ac387d..079a457917f905840aaf29da70c769f4578d0fda 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <stdint.h>
 #include <stdlib.h>
+#include "esp_err.h"
 
 typedef void *bootloader_sha256_handle_t;
 
@@ -30,3 +31,26 @@ bootloader_sha256_handle_t bootloader_sha256_start();
 void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len);
 
 void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest);
+
+/**
+ * @brief Converts an array to a printable string.
+ *
+ * This function is useful for printing SHA-256 digest.
+ * \code{c}
+ * // Example of using. image_hash will be printed
+ * #define HASH_LEN 32 // SHA-256 digest length
+ * ...
+ * char hash_print[HASH_LEN * 2 + 1];
+ * hash_print[HASH_LEN * 2] = 0;
+ * bootloader_sha256_hex_to_str(hash_print, image_hash, HASH_LEN);
+ * ESP_LOGI(TAG, %s", hash_print);
+ * \endcode
+
+ * @param[out] out_str       Output string
+ * @param[in]  in_array_hex  Pointer to input array
+ * @param[in]  len           Length of input array
+ *
+ * @return   ESP_OK: Successful
+ *           ESP_ERR_INVALID_ARG: Error in the passed arguments
+ */
+esp_err_t bootloader_sha256_hex_to_str(char *out_str, const uint8_t *in_array_hex, size_t len);
index 30a9dac441dbe924c615be29945bb5c6290f0b8c..a1749260129883823b2dc40da88e218a85dce7a4 100644 (file)
 #include "bootloader_flash.h"
 #include "bootloader_common.h"
 #include "soc/gpio_periph.h"
+#include "esp_image_format.h"
+#include "bootloader_sha.h"
+
+#define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */
 
 static const char* TAG = "boot_comm";
 
@@ -145,3 +149,46 @@ bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_dat
 
     return ret;
 }
+
+esp_err_t bootloader_common_get_sha256_of_partition (uint32_t address, uint32_t size, int type, uint8_t *out_sha_256)
+{
+    if (out_sha_256 == NULL || size == 0) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    if (type == PART_TYPE_APP) {
+        const esp_partition_pos_t partition_pos = {
+            .offset = address,
+            .size = size,
+        };
+        esp_image_metadata_t data;
+        // Function esp_image_verify() verifies and fills the structure data.
+        // here important to get: image_digest, image_len, hash_appended.
+        if (esp_image_verify(ESP_IMAGE_VERIFY_SILENT, &partition_pos, &data) != ESP_OK) {
+            return ESP_ERR_IMAGE_INVALID;
+        }
+        if (data.image.hash_appended) {
+            memcpy(out_sha_256, data.image_digest, ESP_PARTITION_HASH_LEN);
+            return ESP_OK;
+        }
+        // If image doesn't have a appended hash then hash calculates for entire image.
+        size = data.image_len;
+    }
+    // If image is type by data then hash is calculated for entire image.
+    const void *partition_bin = bootloader_mmap(address, size);
+    if (partition_bin == NULL) {
+        ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", address, size);
+        return ESP_FAIL;
+    }
+    bootloader_sha256_handle_t sha_handle = bootloader_sha256_start();
+    if (sha_handle == NULL) {
+        bootloader_munmap(partition_bin);
+        return ESP_ERR_NO_MEM;
+    }
+    bootloader_sha256_data(sha_handle, partition_bin, size);
+    bootloader_sha256_finish(sha_handle, out_sha_256);
+
+    bootloader_munmap(partition_bin);
+
+    return ESP_OK;
+}
index 73a79956252764e4eb8fb7c8e4850ceccec9e6d2..fe0d756fb599b861c0eecaad58aeae4cb90c8f26 100644 (file)
@@ -39,6 +39,7 @@
 #include "soc/timer_group_reg.h"
 #include "soc/gpio_reg.h"
 #include "soc/gpio_sig_map.h"
+#include "soc/rtc_wdt.h"
 
 #include "sdkconfig.h"
 #include "esp_image_format.h"
@@ -143,7 +144,7 @@ static esp_err_t bootloader_main()
     ets_set_appcpu_boot_addr(0);
 
     /* disable watch dog here */
-    REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );
+    rtc_wdt_disable();
     REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
 
 #ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
index a8d537e04e2ba9cb414bb283f4d0fb58dd936d54..1f7c1b4934bddd9e189c0be5af25555c2884b976 100644 (file)
@@ -169,3 +169,21 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
 }
 
 #endif
+
+esp_err_t bootloader_sha256_hex_to_str(char *out_str, const uint8_t *in_array_hex, size_t len)
+{
+    if (out_str == NULL || in_array_hex == NULL || len == 0) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    for (int i = 0; i < len; i++) {
+        for (int shift = 0; shift < 2; shift++) {
+            uint8_t nibble = (in_array_hex[i] >> (shift ? 0 : 4)) & 0x0F;
+            if (nibble < 10) {
+                out_str[i*2+shift] = '0' + nibble;
+            } else {
+                out_str[i*2+shift] = 'a' + nibble - 10;
+            }
+        }
+    }
+    return ESP_OK;
+}
index e68f8d0d837e5391bb8ec93061d7d05e8c297eb0..5550945bb6f585edf5fdc3dd2b092b8ad6ead51d 100644 (file)
@@ -50,6 +50,7 @@
 #include "bootloader_config.h"
 #include "bootloader_common.h"
 #include "bootloader_utility.h"
+#include "bootloader_sha.h"
 
 static const char* TAG = "boot";
 
@@ -265,7 +266,7 @@ static bool try_load_partition(const esp_partition_pos_t *partition, esp_image_m
         return false;
     }
 #ifdef BOOTLOADER_BUILD
-    if (esp_image_load(ESP_IMAGE_LOAD, partition, data) == ESP_OK) {
+    if (bootloader_load_image(partition, data) == ESP_OK) {
         ESP_LOGI(TAG, "Loaded app from partition at offset 0x%x",
                  partition->offset);
         return true;
index 92acf3b025de522b9a3063cd36ef3e8b9730b516..fea89e6a3722e403f569814cdb56bbad2fb5c137 100644 (file)
@@ -75,7 +75,7 @@ static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t
 static esp_err_t __attribute__((unused)) verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
 static esp_err_t __attribute__((unused)) verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
 
-esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
+static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
 {
 #ifdef BOOTLOADER_BUILD
     bool do_load = (mode == ESP_IMAGE_LOAD);
@@ -128,7 +128,7 @@ esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *
 
     err = verify_image_header(data->start_addr, &data->image, silent);
     if (err != ESP_OK) {
-goto err;
+        goto err;
     }
 
     if (data->image.segment_count > ESP_IMAGE_MAX_SEGMENTS) {
@@ -189,6 +189,17 @@ goto err;
             bootloader_sha256_finish(sha_handle, NULL);
         }
     }
+
+    if (data->image.hash_appended) {
+        const void *hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN);
+        if (hash == NULL) {
+            err = ESP_FAIL;
+            goto err;
+        }
+        memcpy(data->image_digest, hash, HASH_LEN);
+        bootloader_munmap(hash);
+    }
+
     sha_handle = NULL;
     if (err != ESP_OK) {
         goto err;
@@ -224,6 +235,22 @@ goto err;
     return err;
 }
 
+esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data)
+{
+#ifdef BOOTLOADER_BUILD
+    return image_load(ESP_IMAGE_LOAD, part, data);
+#else
+    return ESP_FAIL;
+#endif
+}
+
+esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
+{
+    return image_load(mode, part, data);
+}
+
+esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) __attribute__((alias("esp_image_verify")));
+
 static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent)
 {
     esp_err_t err = ESP_OK;
@@ -446,7 +473,7 @@ esp_err_t esp_image_verify_bootloader(uint32_t *length)
         .offset = ESP_BOOTLOADER_OFFSET,
         .size = ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET,
     };
-    esp_err_t err = esp_image_load(ESP_IMAGE_VERIFY,
+    esp_err_t err = esp_image_verify(ESP_IMAGE_VERIFY,
                                    &bootloader_part,
                                    &data);
     if (length != NULL) {
@@ -556,18 +583,9 @@ static esp_err_t verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_i
 static void debug_log_hash(const uint8_t *image_hash, const char *label)
 {
 #if BOOT_LOG_LEVEL >= LOG_LEVEL_DEBUG
-        char hash_print[sizeof(image_hash)*2 + 1];
-        hash_print[sizeof(image_hash)*2] = 0;
-        for (int i = 0; i < sizeof(image_hash); i++) {
-            for (int shift = 0; shift < 2; shift++) {
-                uint8_t nibble = (image_hash[i] >> (shift ? 0 : 4)) & 0x0F;
-                if (nibble < 10) {
-                    hash_print[i*2+shift] = '0' + nibble;
-                } else {
-                    hash_print[i*2+shift] = 'a' + nibble - 10;
-                }
-            }
-        }
-        ESP_LOGD(TAG, "%s: %s", label, hash_print);
+    char hash_print[HASH_LEN * 2 + 1];
+    hash_print[HASH_LEN * 2] = 0;
+    bootloader_sha256_hex_to_str(hash_print, image_hash, HASH_LEN);
+    ESP_LOGD(TAG, "%s: %s", label, hash_print);
 #endif
 }
index a9e8f8f9bacd57fce8c6fec2deae89e7c7e85757..2b229c00b7a9fe610700cd73ad2e171a9c143d38 100644 (file)
@@ -281,7 +281,7 @@ static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partit
     if (partition->type == PART_TYPE_APP) {
       /* check if the partition holds a valid unencrypted app */
       esp_image_metadata_t data_ignored;
-      err = esp_image_load(ESP_IMAGE_VERIFY,
+      err = esp_image_verify(ESP_IMAGE_VERIFY,
                            &partition->pos,
                            &data_ignored);
       should_encrypt = (err == ESP_OK);
index 7994667f33480525782da3be7008dd056c282bf5..153a859c29d2c2fa0bb2bfea4ff6f3b860ae3acd 100644 (file)
@@ -25,7 +25,7 @@ TEST_CASE("Verify bootloader image in flash", "[bootloader_support]")
         .size = ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET,
     };
     esp_image_metadata_t data = { 0 };
-    TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_image_load(ESP_IMAGE_VERIFY, &fake_bootloader_partition, &data));
+    TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_image_verify(ESP_IMAGE_VERIFY, &fake_bootloader_partition, &data));
     TEST_ASSERT_NOT_EQUAL(0, data.image_len);
 
     uint32_t bootloader_length = 0;
@@ -43,7 +43,7 @@ TEST_CASE("Verify unit test app image", "[bootloader_support]")
         .size = running->size,
     };
 
-    TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_image_load(ESP_IMAGE_VERIFY, &running_pos, &data));
+    TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data));
     TEST_ASSERT_NOT_EQUAL(0, data.image_len);
     TEST_ASSERT_TRUE(data.image_len <= running->size);
 }
index f9589a9142864eb1655d73420d2f4a7f7b1ebb68..5d996c0a8b08cd9858f7ba0777294011ad564ec9 100644 (file)
@@ -1009,6 +1009,15 @@ config BT_BLE_DYNAMIC_ENV_MEMORY
     help
         This select can make the allocation of memory will become more flexible
 
+config BLE_HOST_QUEUE_CONGESTION_CHECK
+    bool "BLE queue congestion check"
+    depends on BLUEDROID_ENABLED
+    default n
+    help
+        When scanning and scan duplicate is not enabled, if there are a lot of adv packets around or application layer 
+        handling adv packets is slow, it will cause the controller memory to run out. if enabled, adv packets will be 
+        lost when host queue is congested.
+
 config BLE_SCAN_DUPLICATE
     bool "BLE Scan Duplicate Options "
     depends on BLUEDROID_ENABLED
@@ -1019,8 +1028,8 @@ config BLE_SCAN_DUPLICATE
 config DUPLICATE_SCAN_CACHE_SIZE
     int "Maximum number of devices in scan duplicate filter"
     depends on BLE_SCAN_DUPLICATE
-    range 10 200
-    default 20
+    range 10 1000
+    default 50
     help
         Maximum number of devices which can be recorded in scan duplicate filter.
         When the maximum amount of device in the filter is reached, the cache will be refreshed.
@@ -1035,8 +1044,8 @@ config BLE_MESH_SCAN_DUPLICATE_EN
 config MESH_DUPLICATE_SCAN_CACHE_SIZE
     int "Maximum number of Mesh adv packets in scan duplicate filter"
     depends on BLE_MESH_SCAN_DUPLICATE_EN
-    range 10 200
-    default 50
+    range 10 1000
+    default 100
     help
         Maximum number of adv packets which can be recorded in duplicate scan cache for BLE Mesh.
         When the maximum amount of device in the filter is reached, the cache will be refreshed.
index fc431d6fb4b036af90c659dd71884c422354a53f..578916e5f29d445461b20d26f35dc8227b9b71fd 100644 (file)
@@ -164,6 +164,7 @@ esp_gatt_status_t esp_ble_gattc_get_all_char(esp_gatt_if_t gattc_if,
     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
 
     if ((start_handle == 0) && (end_handle == 0)) {
+        *count = 0;
         return ESP_GATT_INVALID_HANDLE;
     }
 
@@ -206,6 +207,7 @@ esp_gatt_status_t esp_ble_gattc_get_char_by_uuid(esp_gatt_if_t gattc_if,
     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
 
     if (start_handle == 0 && end_handle == 0) {
+        *count = 0;
         return ESP_GATT_INVALID_HANDLE;
     }
 
@@ -247,6 +249,7 @@ esp_gatt_status_t esp_ble_gattc_get_descr_by_char_handle(esp_gatt_if_t gattc_if,
     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
 
     if (char_handle == 0) {
+        *count = 0;
         return ESP_GATT_INVALID_HANDLE;
     }
     
@@ -269,6 +272,7 @@ esp_gatt_status_t esp_ble_gattc_get_include_service(esp_gatt_if_t gattc_if,
     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
 
     if (start_handle == 0 && end_handle == 0) {
+        *count = 0;
         return ESP_GATT_INVALID_HANDLE;
     }
 
@@ -291,6 +295,7 @@ esp_gatt_status_t esp_ble_gattc_get_attr_count(esp_gatt_if_t gattc_if,
     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
 
     if ((start_handle == 0 && end_handle == 0) && (type != ESP_GATT_DB_DESCRIPTOR)) {
+        *count = 0;
         return ESP_GATT_INVALID_HANDLE;
     }
 
@@ -308,6 +313,7 @@ esp_gatt_status_t esp_ble_gattc_get_db(esp_gatt_if_t gattc_if, uint16_t conn_id,
     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
 
     if (start_handle == 0 && end_handle == 0) {
+        *count = 0;
         return ESP_GATT_INVALID_HANDLE;
     }
 
index bc97b76e46f8f5ac240831d511d668b7632031c7..d25d297806b7617366b2958015d4605da4ee2249 100644 (file)
@@ -350,7 +350,8 @@ esp_err_t esp_ble_gatts_create_attr_tab(const esp_gatts_attr_db_t *gatts_attr_db
                                             uint8_t max_nb_attr,
                                             uint8_t srvc_inst_id);
 /**
- * @brief           This function is called to add an included service. After included
+ * @brief           This function is called to add an included service. This function have to be called between 
+ *                  'esp_ble_gatts_create_service' and 'esp_ble_gatts_add_char'.  After included
  *                  service is included, a callback event BTA_GATTS_ADD_INCL_SRVC_EVT
  *                  is reported the included service ID.
  *
index 7c8ec58c6446ba8069a2679dea8a14390994275f..90a9d13502271f9a5839a1c3db3e141e8b000192 100644 (file)
@@ -376,14 +376,8 @@ static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(tBTA_GATTC_SERV *p_srvc_cb,
         isvc->included_service = bta_gattc_find_matching_service(
                                     p_srvc_cb->p_srvc_cache, incl_srvc_s_handle);
         if (!isvc->included_service) {
-            // if it is a secondary service, wait to update later
-            if(property == 0){
-                p_srvc_cb->update_sec_sev = true;   
-            } else {
-                APPL_TRACE_ERROR("%s: Illegal action to add non-existing included service!", __func__);
-                osi_free(isvc);
-                return GATT_WRONG_STATE;
-            }
+            // if can't find included service, wait to update later
+            p_srvc_cb->update_incl_srvc = true;
         }
 
         list_append(service->included_svc, isvc);
@@ -606,10 +600,10 @@ static void bta_gattc_explore_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
             return;
         }
     }
-    //update include service when have secondary service
-    if(p_srvc_cb->update_sec_sev) {
+    // if update_incl_srvc is true, update include service
+    if(p_srvc_cb->update_incl_srvc) {
         bta_gattc_update_include_service(p_srvc_cb->p_srvc_cache);
-        p_srvc_cb->update_sec_sev = false;
+        p_srvc_cb->update_incl_srvc = false;
     }
     /* no service found at all, the end of server discovery*/
     APPL_TRACE_DEBUG("%s no more services found", __func__);
@@ -1658,7 +1652,8 @@ void bta_gattc_get_db_size_handle(UINT16 conn_id, UINT16 start_handle, UINT16 en
     tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
 
     if (p_clcb == NULL) {
-        return NULL;
+        *count = 0;
+        return;
     }
     
     tBTA_GATTC_SERV *p_srcb = p_clcb->p_srcb;
index 2b550d908d971196ee16f687ae742d6788b9d8df..68887f0891cdd28ff5f3eaf47ca4cccad5045f6a 100644 (file)
@@ -300,7 +300,7 @@ typedef struct {
     UINT16              attr_index;     /* cahce NV saving/loading attribute index */
 
     UINT16              mtu;
-    bool                update_sec_sev;
+    bool                update_incl_srvc;
 } tBTA_GATTC_SERV;
 
 #ifndef BTA_GATTC_NOTIF_REG_MAX
index 744edc91795fc48621a9a6cc5172f73551115bb2..20b0cc78551e4917d3e77796bd76f641abf73599 100644 (file)
@@ -46,7 +46,7 @@ static const tBTM_ESCO_PARAMS bta_hf_client_esco_params[] = {
         BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
         BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
         BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
-        .retrans_effort = BTM_ESCO_RETRANS_POWER,
+        .retrans_effort = BTM_ESCO_RETRANS_OFF,
     },
     /* ESCO CVSD */
     {
index 531994bc5f9398480673d48e6923b3b8ec8ba564..f89ba3e0ba842623b1c8ac649feb8e168ac94c24 100644 (file)
@@ -22,7 +22,6 @@
  *
  ******************************************************************************/
 
-#include <arpa/inet.h>
 #include <pthread.h>
 #include <stdlib.h>
 
index 8876f8c1728ed3bf3d992d14e4bf1a54a075bc4c..573ff31da726f399354d4af7e5ea7dd5a9239b21 100644 (file)
@@ -182,6 +182,10 @@ static void btc_dm_remove_ble_bonding_keys(void)
 
 static void btc_dm_save_ble_bonding_keys(void)
 {
+    if(!(pairing_cb.ble.is_penc_key_rcvd || pairing_cb.ble.is_pid_key_rcvd || pairing_cb.ble.is_pcsrk_key_rcvd || 
+         pairing_cb.ble.is_lenc_key_rcvd || pairing_cb.ble.is_lcsrk_key_rcvd || pairing_cb.ble.is_lidk_key_rcvd)) {
+        return ;
+    }
     bt_bdaddr_t bd_addr;
 
     bdcpy(bd_addr.address, pairing_cb.bd_addr);
index b8afbb5814346f698bc5f4b30bbef5f805056ed8..1022e770d1d478457944f5f59f67a89e4637cf94 100644 (file)
@@ -170,6 +170,9 @@ int btc_init(void)
         return BT_STATUS_NOMEM;
     }
     btc_gap_callback_init();
+#if SCAN_QUEUE_CONGEST_CHECK
+    btc_adv_list_init();
+#endif
     /* TODO: initial the profile_tab */
     return BT_STATUS_SUCCESS;
 }
@@ -178,7 +181,18 @@ void btc_deinit(void)
 {
     vTaskDelete(xBtcTaskHandle);
     vQueueDelete(xBtcQueue);
-
+#if SCAN_QUEUE_CONGEST_CHECK
+    btc_adv_list_deinit();
+#endif
     xBtcTaskHandle = NULL;
     xBtcQueue = 0;
 }
+
+bool btc_check_queue_is_congest(void)
+{
+    UBaseType_t wait_size = uxQueueMessagesWaiting(xBtcQueue);
+    if(wait_size >= QUEUE_CONGEST_SIZE) {
+        return true;
+    }
+    return false;
+}
index f644e865a6b4658f467d34f74842830563c352d1..5813c521783067fb10311eb64d778d4938f47e9b 100644 (file)
@@ -28,6 +28,11 @@ typedef struct btc_msg {
     void   *arg;    //param for btc function or function param
 } btc_msg_t;
 
+typedef struct btc_adv_packet {
+    uint8_t addr[6];
+    uint8_t addr_type;
+} btc_adv_packet_t;
+
 typedef enum {
     BTC_SIG_API_CALL = 0,   // APP TO STACK
     BTC_SIG_API_CB,         // STACK TO APP
@@ -72,5 +77,6 @@ bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg
 
 int btc_init(void);
 void btc_deinit(void);
+bool btc_check_queue_is_congest(void);
 
 #endif /* __BTC_TASK_H__ */
index 7457555685d0227ba30825dab91ae83b732deba4..faf23eefc7d4bacc6e9b90d7807c5f77df7816e5 100644 (file)
@@ -763,7 +763,7 @@ static void btc_a2dp_sink_thread_init(UNUSED_ATTR void *context)
 
     btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_ON;
 
-    btc_aa_snk_cb.RxSbcQ = fixed_queue_new(SIZE_MAX);
+    btc_aa_snk_cb.RxSbcQ = fixed_queue_new(QUEUE_SIZE_MAX);
 
     btc_a2dp_control_init();
 }
index da5ff32b9608d8b5d15dc71aa10f09c689040ec3..590c382ffe75c1c923f301d2d31acb2375101ac1 100644 (file)
@@ -1616,7 +1616,7 @@ static void btc_a2dp_source_thread_init(UNUSED_ATTR void *context)
 
     btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_ON;
 
-    btc_aa_src_cb.TxAaQ = fixed_queue_new(SIZE_MAX);
+    btc_aa_src_cb.TxAaQ = fixed_queue_new(QUEUE_SIZE_MAX);
 
     btc_a2dp_control_init();
 }
index b55527b74bea56816246d8cac60bdfbb218caaba..c8951db4c446c7f965afd04b7bc1d703ba2bb466 100644 (file)
 #include "btc/btc_ble_storage.h"
 #include "btc/btc_dm.h"
 #include "btc/btc_util.h"
+#include "osi/mutex.h"
 
 static tBTA_BLE_ADV_DATA gl_bta_adv_data;
 static tBTA_BLE_ADV_DATA gl_bta_scan_rsp_data;
+#if SCAN_QUEUE_CONGEST_CHECK
+static list_t *adv_filter_list;
+static osi_mutex_t adv_list_lock;
+bool btc_check_adv_list(uint8_t * addr, uint8_t addr_type);
+uint32_t btc_get_adv_list_length(void);
+void btc_adv_list_refresh(void);
+void btc_adv_list_lock(void);
+void btc_adv_list_unlock(void);
+static uint16_t btc_adv_list_count = 0;
+
+#define  BTC_ADV_LIST_MAX_LENGTH    50
+#define  BTC_ADV_LIST_MAX_COUNT     200
+#endif
 
 static inline void btc_gap_ble_cb_to_app(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
 {
@@ -510,6 +524,19 @@ static void btc_search_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data
     param.scan_rst.search_evt = event;
     switch (event) {
     case BTA_DM_INQ_RES_EVT: {
+#if SCAN_QUEUE_CONGEST_CHECK
+        if(btc_check_queue_is_congest()) {
+            BTC_TRACE_DEBUG("BtcQueue is congested");
+            if(btc_get_adv_list_length() > BTC_ADV_LIST_MAX_LENGTH || btc_adv_list_count > BTC_ADV_LIST_MAX_COUNT) {
+                btc_adv_list_refresh();
+                btc_adv_list_count = 0;
+            }
+            if(btc_check_adv_list(p_data->inq_res.bd_addr, p_data->inq_res.ble_addr_type)) {
+                return;
+            }
+        }
+        btc_adv_list_count ++;
+#endif
         bdcpy(param.scan_rst.bda, p_data->inq_res.bd_addr);
         param.scan_rst.dev_type = p_data->inq_res.device_type;
         param.scan_rst.rssi = p_data->inq_res.rssi;
@@ -585,6 +612,9 @@ static void btc_stop_scan_callback(tBTA_STATUS status)
     if (ret != BT_STATUS_SUCCESS) {
         BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
     }
+#if SCAN_QUEUE_CONGEST_CHECK
+    btc_adv_list_refresh();
+#endif
 }
 
 void btc_update_conn_param_callback (UINT8 status, BD_ADDR bd_addr, tBTM_LE_UPDATE_CONN_PRAMS *update_conn_params)
@@ -725,6 +755,9 @@ static void btc_ble_start_scanning(uint32_t duration,
                                    tBTA_START_STOP_SCAN_CMPL_CBACK *start_scan_cb)
 {
     if ((results_cb != NULL) && (start_scan_cb != NULL)) {
+#if SCAN_QUEUE_CONGEST_CHECK
+        btc_adv_list_refresh();
+#endif
         //Start scan the device
         BTA_DmBleScan(true, duration, results_cb, start_scan_cb);
     } else {
@@ -1134,3 +1167,99 @@ void btc_gap_ble_deinit(void)
     btc_cleanup_adv_data(&gl_bta_adv_data);
     btc_cleanup_adv_data(&gl_bta_scan_rsp_data);
 }
+
+#if SCAN_QUEUE_CONGEST_CHECK
+void btc_adv_list_free(void *data)
+{
+    osi_free(data);
+}
+
+void btc_adv_list_init(void)
+{
+    osi_mutex_new(&adv_list_lock);
+    adv_filter_list = list_new(btc_adv_list_free);
+}
+
+void btc_adv_list_deinit(void)
+{
+    osi_mutex_free(&adv_list_lock);
+    if(adv_filter_list) {
+        list_free(adv_filter_list);
+        adv_filter_list = NULL;
+    }
+}
+void btc_adv_list_add_packet(void * data)
+{
+    if(!data) {
+        BTC_TRACE_ERROR("%s data is NULL", __func__);
+        return;
+    }
+    btc_adv_list_lock();
+    list_prepend(adv_filter_list, data);
+    btc_adv_list_unlock();
+}
+
+uint32_t btc_get_adv_list_length(void)
+{
+    if(!adv_filter_list) {
+        BTC_TRACE_ERROR("%s adv_filter_list is NULL", __func__);
+        return 0;
+    }
+    btc_adv_list_lock();
+    size_t length = list_length(adv_filter_list);
+    btc_adv_list_unlock();
+
+    return length;
+}
+
+void btc_adv_list_refresh(void)
+{
+    if(!adv_filter_list) {
+        BTC_TRACE_ERROR("%s adv_filter_list is NULL", __func__);
+        return ;
+    }
+    btc_adv_list_lock();
+    list_clear(adv_filter_list);
+    btc_adv_list_unlock();
+}
+
+bool btc_check_adv_list(uint8_t * addr, uint8_t addr_type)
+{
+    bool found = false;
+    if(!adv_filter_list || !addr) {
+        BTC_TRACE_ERROR("%s adv_filter_list is NULL", __func__);
+        return found;
+    }
+
+    btc_adv_list_lock();
+    for (const list_node_t *node = list_begin(adv_filter_list); node != list_end(adv_filter_list); node = list_next(node)) {
+        btc_adv_packet_t *packet = (btc_adv_packet_t *)list_node(node);
+        if(!bdcmp(addr, packet->addr) && packet->addr_type == addr_type) {
+            found = true;
+            break;
+        }
+     }
+     btc_adv_list_unlock();
+     if(!found) {
+         btc_adv_packet_t *adv_packet = osi_malloc(sizeof(btc_adv_packet_t));
+         if(adv_packet) {
+             adv_packet->addr_type = addr_type;
+             bdcpy(adv_packet->addr, addr);
+             btc_adv_list_add_packet(adv_packet);
+         } else {
+             BTC_TRACE_ERROR("%s adv_packet malloc failed", __func__);
+         }
+     }
+    return found;
+}
+
+void btc_adv_list_lock(void)
+{
+    osi_mutex_lock(&adv_list_lock, OSI_MUTEX_MAX_TIMEOUT);
+}
+
+void btc_adv_list_unlock(void)
+{
+    osi_mutex_unlock(&adv_list_lock);
+}
+#endif
index d48cd0b40b21ef31f1a290dd965b97316664e637..bb7d6cbbdfc2a931adadfd9fa12adf08dfc59885 100644 (file)
@@ -331,6 +331,7 @@ esp_gatt_status_t btc_ble_gattc_get_service(uint16_t conn_id, esp_bt_uuid_t *svc
         if (bta_uuid) {
             osi_free(bta_uuid);
         }
+        *count = 0;
         return status;
     } else {
         btc_gattc_fill_gatt_db_conversion(*count, (uint16_t)svc_num, ESP_GATT_DB_PRIMARY_SERVICE, offset, (void *)result, db);
@@ -362,6 +363,7 @@ esp_gatt_status_t btc_ble_gattc_get_all_char(uint16_t conn_id,
         if (db) {
             osi_free(db);
         }
+        *count = 0;
         return status;
     } else {
         btc_gattc_fill_gatt_db_conversion(*count, (uint16_t)char_num, ESP_GATT_DB_CHARACTERISTIC, offset, (void *)result, db);
@@ -389,6 +391,7 @@ esp_gatt_status_t btc_ble_gattc_get_all_descr(uint16_t conn_id,
         if (db) {
             osi_free(db);
         }
+        *count = 0;
         return status;
     } else {
         btc_gattc_fill_gatt_db_conversion(*count, (uint16_t)descr_num, ESP_GATT_DB_DESCRIPTOR, offset, (void *)result, db);
@@ -420,6 +423,7 @@ esp_gatt_status_t btc_ble_gattc_get_char_by_uuid(uint16_t conn_id,
         if (db) {
             osi_free(db);
         }
+        *count = 0;
         return status;
     } else {
         btc_gattc_fill_gatt_db_conversion(*count, (uint16_t)char_num, ESP_GATT_DB_CHARACTERISTIC, 0, (void *)result, db);
@@ -456,6 +460,7 @@ esp_gatt_status_t btc_ble_gattc_get_descr_by_uuid(uint16_t conn_id,
         if (db) {
             osi_free(db);
         }
+        *count = 0;
         return status;
     } else {
         btc_gattc_fill_gatt_db_conversion(*count, (uint16_t)descr_num, ESP_GATT_DB_DESCRIPTOR, 0, (void *)result, db);
@@ -487,6 +492,7 @@ esp_gatt_status_t btc_ble_gattc_get_descr_by_char_handle(uint16_t conn_id,
         if (db) {
             osi_free(db);
         }
+        *count = 0;
         return status;
     } else {
         btc_gattc_fill_gatt_db_conversion(*count, (uint16_t)descr_num, ESP_GATT_DB_DESCRIPTOR, 0, (void *)result, db);
@@ -524,6 +530,7 @@ esp_gatt_status_t btc_ble_gattc_get_include_service(uint16_t conn_id,
         if (db) {
             osi_free(db);
         }
+        *count = 0;
         return status;
     }else {
         btc_gattc_fill_gatt_db_conversion(*count, (uint16_t)incl_num, ESP_GATT_DB_INCLUDED_SERVICE, 0, (void *)result, db);
@@ -566,6 +573,7 @@ esp_gatt_status_t btc_ble_gattc_get_db(uint16_t conn_id, uint16_t start_handle,
         if (get_db) {
             osi_free(get_db);
         }
+        *count = 0;
         return ESP_GATT_NOT_FOUND;
     }
 
@@ -579,7 +587,7 @@ esp_gatt_status_t btc_ble_gattc_get_db(uint16_t conn_id, uint16_t start_handle,
         btc128_to_bta_uuid(&bta_uuid, get_db[i].uuid.uu);
         bta_to_btc_uuid(&db[i].uuid, &bta_uuid);
     }
-    *count = num;
+    *count = db_size;
     //don't forget to free the db buffer after used.
     if (get_db) {
         osi_free(get_db);
index 9ee03d4117168daecdd2514669b0341bc8eab2e1..c9e0f5645af214a42b13b3becea727d194b665e9 100644 (file)
@@ -166,5 +166,7 @@ void btc_gap_ble_cb_deep_free(btc_msg_t *msg);
 void btc_gap_ble_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
 void btc_gap_callback_init(void);
 void btc_gap_ble_deinit(void);
+void btc_adv_list_init(void);
+void btc_adv_list_deinit(void);
 
 #endif /* __BTC_GAP_BLE_H__ */
index 51ba9a9de1b5c66399f1dffb045a1dd20426b06e..77719bc8471be70b31378541f623c42ac3696831 100644 (file)
@@ -26,9 +26,6 @@
 
 #define UNUSED(x)                   (void)(x)
 
-#ifndef SIZE_MAX
-#define SIZE_MAX                    254
-#endif
 /*Timer Related Defination*/
 
 //by Snake.T
index 202174c310947f959affe855393cd9f521de758b..7782526d02d90dbc5ee17fe63f4d42ac1a447153 100644 (file)
 #define BTA_AV_CO_CP_SCMS_T  FALSE//FALSE
 #endif
 
+#ifndef QUEUE_CONGEST_SIZE
+#define  QUEUE_CONGEST_SIZE    40
+#endif
+
+#ifndef CONFIG_BLE_HOST_QUEUE_CONGESTION_CHECK
+#define SCAN_QUEUE_CONGEST_CHECK  FALSE
+#else
+#define SCAN_QUEUE_CONGEST_CHECK  CONFIG_BLE_HOST_QUEUE_CONGESTION_CHECK
+#endif
+
 /* This feature is used to eanble interleaved scan*/
 #ifndef BTA_HOST_INTERLEAVE_SEARCH
 #define BTA_HOST_INTERLEAVE_SEARCH FALSE//FALSE
 
 /* Include Out-of-Band implementation for Simple Pairing */
 #ifndef BTM_OOB_INCLUDED
-#define BTM_OOB_INCLUDED                FALSE//TRUE
+#define BTM_OOB_INCLUDED                TRUE
 #endif
 
 /* TRUE to include Sniff Subrating */
index 5f8fc949cbb5491df8f7923108b8ff924d3505db..e910aa7b73102f96150e0ad703a69099c024b3c7 100644 (file)
@@ -36,6 +36,7 @@
 #define HCI_BLE_EVENT 0x3e
 #define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2)
 #define PACKET_TYPE_TO_INDEX(type) ((type) - 1)
+extern bool BTU_check_queue_is_congest(void);
 
 
 static const uint8_t preamble_sizes[] = {
@@ -105,7 +106,7 @@ static bool hal_open(const hci_hal_callbacks_t *upper_callbacks)
     assert(upper_callbacks != NULL);
     callbacks = upper_callbacks;
 
-    hci_hal_env_init(HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX);
+    hci_hal_env_init(HCI_HAL_SERIAL_BUFFER_SIZE, QUEUE_SIZE_MAX);
 
     xHciH4Queue = xQueueCreate(HCI_H4_QUEUE_LEN, sizeof(BtTaskEvt_t));
     xTaskCreatePinnedToCore(hci_hal_h4_rx_handler, HCI_H4_TASK_NAME, HCI_H4_TASK_STACK_SIZE, NULL, HCI_H4_TASK_PRIO, &xHciH4TaskHandle, HCI_H4_TASK_PINNED_TO_CORE);
@@ -185,7 +186,6 @@ task_post_status_t hci_hal_h4_task_post(task_post_t timeout)
     evt.par = 0;
 
     if (xQueueSend(xHciH4Queue, &evt, timeout) != pdTRUE) {
-        HCI_TRACE_ERROR("xHciH4Queue failed\n");
         return TASK_POST_SUCCESS;
     }
 
@@ -222,6 +222,14 @@ static void hci_packet_complete(BT_HDR *packet){
 }
 #endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
 
+bool host_recv_adv_packet(BT_HDR *packet)
+{
+    assert(packet);
+    if(packet->data[0] == DATA_TYPE_EVENT && packet->data[1] == HCI_BLE_EVENT && packet->data[3] ==  HCI_BLE_ADV_PKT_RPT_EVT) {
+        return true;
+    }
+    return false;
+}
 
 static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet)
 {
@@ -276,6 +284,13 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet)
         hci_hal_env.allocator->free(packet);
         return;
     }
+#if SCAN_QUEUE_CONGEST_CHECK
+    if(BTU_check_queue_is_congest() && host_recv_adv_packet(packet)) {
+        HCI_TRACE_ERROR("BtuQueue is congested");
+        hci_hal_env.allocator->free(packet);
+        return;
+    }
+#endif
 
     packet->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)];
     callbacks->packet_ready(packet);
@@ -318,7 +333,7 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len)
     pkt->layer_specific = 0;
     memcpy(pkt->data, data, len);
     fixed_queue_enqueue(hci_hal_env.rx_q, pkt);
-    hci_hal_h4_task_post(TASK_POST_BLOCKING);
+    hci_hal_h4_task_post(100 / portTICK_PERIOD_MS);
 
     BTTRC_DUMP_BUFFER("Recv Pkt", pkt->data, len);
 
index ec68663864948b580e2e79fea8632f682e0dbc8a..b2120593ab67cc1c3b7653818e6af460674322fc 100644 (file)
@@ -158,7 +158,7 @@ static int hci_layer_init_env(void)
     // as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control)
     // This value can change when you get a command complete or command status event.
     hci_host_env.command_credits = 1;
-    hci_host_env.command_queue = fixed_queue_new(SIZE_MAX);
+    hci_host_env.command_queue = fixed_queue_new(QUEUE_SIZE_MAX);
     if (hci_host_env.command_queue) {
         fixed_queue_register_dequeue(hci_host_env.command_queue, event_command_ready);
     } else {
@@ -166,7 +166,7 @@ static int hci_layer_init_env(void)
         return -1;
     }
 
-    hci_host_env.packet_queue = fixed_queue_new(SIZE_MAX);
+    hci_host_env.packet_queue = fixed_queue_new(QUEUE_SIZE_MAX);
     if (hci_host_env.packet_queue) {
         fixed_queue_register_dequeue(hci_host_env.packet_queue, event_packet_ready);
     } else {
index e3bf2f67b516313a61bea0177f5d6ac71f5ec2dc..5ec0c07498f02dae4c9d9ebaa431eba63314b573 100644 (file)
 #include <stdbool.h>
 #include "osi/list.h"
 
+#ifndef QUEUE_SIZE_MAX
+#define QUEUE_SIZE_MAX                    254
+#endif
+
 struct fixed_queue_t;
 
 typedef struct fixed_queue_t fixed_queue_t;
index 8bb2fdc7c04add1fe7bdd5707777b5e8cd2a2c5c..1aa773c0184b4b86dd82b0917924faeaddecf6d1 100644 (file)
@@ -69,7 +69,7 @@ typedef enum {
 #define HCI_H4_TASK_STACK_SIZE          (2048 + BT_TASK_EXTRA_STACK_SIZE)
 #define HCI_H4_TASK_PRIO                (configMAX_PRIORITIES - 4)
 #define HCI_H4_TASK_NAME                "hciH4T"
-#define HCI_H4_QUEUE_LEN                60
+#define HCI_H4_QUEUE_LEN                1
 
 #define BTU_TASK_PINNED_TO_CORE         (TASK_PINNED_TO_CORE)
 #define BTU_TASK_STACK_SIZE             (4096 + BT_TASK_EXTRA_STACK_SIZE)
index 7d5ba3a16e3a0f0f353392602f88a98cbd0f9128..61f6c9a556e6ef4de18f0bd0e5b461018ca95a8d 100644 (file)
@@ -313,7 +313,7 @@ tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr)
             p_lcb->allocated = (UINT8)(i + 1);
             memcpy(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN);
             AVCT_TRACE_DEBUG("avct_lcb_alloc %d", p_lcb->allocated);
-            p_lcb->tx_q = fixed_queue_new(SIZE_MAX);
+            p_lcb->tx_q = fixed_queue_new(QUEUE_SIZE_MAX);
             break;
         }
     }
index 5e1a1f46de28f6a408df3d5fb7652add6b876717..035488f85451dd84035fbc9a78d802e236bee4ec 100644 (file)
@@ -376,8 +376,8 @@ tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr)
         if (!p_ccb->allocated) {
             p_ccb->allocated = TRUE;
             memcpy(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN);
-            p_ccb->cmd_q = fixed_queue_new(SIZE_MAX);
-            p_ccb->rsp_q = fixed_queue_new(SIZE_MAX);
+            p_ccb->cmd_q = fixed_queue_new(QUEUE_SIZE_MAX);
+            p_ccb->rsp_q = fixed_queue_new(QUEUE_SIZE_MAX);
             p_ccb->timer_entry.param = (UINT32) p_ccb;
             AVDT_TRACE_DEBUG("avdt_ccb_alloc %d\n", i);
             break;
index 92e3dcad9ded13939215687e731e37930dd7ba79..3227fa69b38d9da11c9c71df375e879ff748021f 100644 (file)
@@ -412,6 +412,7 @@ void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
 {
     tAVDT_TC_TBL    *p_tbl;
     UINT16          disc_rsn = AVDT_DISC_RSN_NORMAL;
+    tAVDT_CCB       *p_ccb;
     AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d\n",
                      lcid, ack_needed);
     /* look up info for this channel */
@@ -420,7 +421,13 @@ void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
             /* send L2CAP disconnect response */
             L2CA_DisconnectRsp(lcid);
         } else {
-            disc_rsn = AVDT_DISC_RSN_ABNORMAL;
+            if ((p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx)) != NULL) {
+                UINT16 rsn = L2CA_GetDisconnectReason(p_ccb->peer_addr, BT_TRANSPORT_BR_EDR);
+                if (rsn != 0 && rsn != HCI_ERR_PEER_USER) {
+                    disc_rsn = AVDT_DISC_RSN_ABNORMAL;
+                    AVDT_TRACE_EVENT("avdt link disc rsn 0x%x", rsn);
+                }
+            }
         }
 
         avdt_ad_tc_close_ind(p_tbl, disc_rsn);
index cf3c1ad331bffad27a00f097a479656e17393e4b..ac6cbce3888a6a862f03632feea1d848829740aa 100644 (file)
@@ -603,7 +603,7 @@ tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs)
             memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS));
 #if AVDT_MULTIPLEXING == TRUE
             /* initialize fragments gueue */
-            p_scb->frag_q = fixed_queue_new(SIZE_MAX);
+            p_scb->frag_q = fixed_queue_new(QUEUE_SIZE_MAX);
 
             if (p_cs->cfg.psc_mask & AVDT_PSC_MUX) {
                 p_scb->cs.cfg.mux_tcid_media = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
index 664a3d2cb9d3072397e3712bd04ee09be6d33751..765265fe1e805843e6d7d39b01c5762a7b015145 100644 (file)
@@ -1225,7 +1225,7 @@ void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY
 
             /* Set that link key is known since this shares field with BTM_SEC_FLAG_LKEY_KNOWN flag in stack/btm_api.h*/
             p_rec->sec_flags |=  BTM_SEC_LE_LINK_KEY_KNOWN;
-            if ( p_keys->pcsrk_key.sec_level == SMP_SEC_AUTHENTICATED) {
+            if ( p_keys->lenc_key.sec_level == SMP_SEC_AUTHENTICATED) {
                 p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED;
             } else {
                 p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED;
index 40f2e8fe923377a0592e9b4b18074ac43507c804..d36e32a1118ddc56d0a20f70ef38b57575dfe354 100644 (file)
@@ -3867,7 +3867,7 @@ void btm_ble_init (void)
     btm_cb.cmn_ble_vsc_cb.values_read = FALSE;
     p_cb->cur_states       = 0;
 
-    p_cb->conn_pending_q = fixed_queue_new(SIZE_MAX);
+    p_cb->conn_pending_q = fixed_queue_new(QUEUE_SIZE_MAX);
 
     p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
     p_cb->inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
index d1ba6acba6bbb9d5c86040b8a92343f672d2950a..579e8d645302a021b1cf867dcbd4a90fa0ba925e 100644 (file)
@@ -56,8 +56,8 @@ void btm_init (void)
 #endif /* #if BTM_DYNAMIC_MEMORY */
     /* All fields are cleared; nonzero fields are reinitialized in appropriate function */
     memset(&btm_cb, 0, sizeof(tBTM_CB));
-    btm_cb.page_queue = fixed_queue_new(SIZE_MAX);
-    btm_cb.sec_pending_q = fixed_queue_new(SIZE_MAX);
+    btm_cb.page_queue = fixed_queue_new(QUEUE_SIZE_MAX);
+    btm_cb.sec_pending_q = fixed_queue_new(QUEUE_SIZE_MAX);
 
 #if defined(BTM_INITIAL_TRACE_LEVEL)
     btm_cb.trace_level = BTM_INITIAL_TRACE_LEVEL;
index 47e3483b97021c4d64d1f71f2e0d77fbe8ba36ee..6b8a32befd7b63ec9d3df36937248a0cab4b3b86 100644 (file)
@@ -113,7 +113,7 @@ void btm_sco_init (void)
 #endif
 #if (BTM_SCO_HCI_INCLUDED == TRUE)
     for (int i = 0; i < BTM_MAX_SCO_LINKS; i++) {
-        btm_cb.sco_cb.sco_db[i].xmit_data_q = fixed_queue_new(SIZE_MAX);
+        btm_cb.sco_cb.sco_db[i].xmit_data_q = fixed_queue_new(QUEUE_SIZE_MAX);
     }
 #endif
     /* Initialize nonzero defaults */
index 0b71a3f1f54233559c90edd8d121fa74f4609738..29b2ac50ff070a2d6984a1120b4a1f118340fa6e 100644 (file)
@@ -1361,7 +1361,7 @@ tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBT_TRANSPORT transport, tBTM_SE
 
         return (BTM_SUCCESS);
     }
-
+    p_dev_rec->enc_init_by_we = TRUE;
     /* enqueue security request if security is active */
     if (p_dev_rec->p_callback || (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE)) {
         BTM_TRACE_WARNING ("Security Manager: BTM_SetEncryption busy, enqueue request\n");
@@ -2762,7 +2762,7 @@ void btm_sec_check_pending_reqs (void)
         /* Now, re-submit anything in the mux queue */
         bq = btm_cb.sec_pending_q;
         if (!btm_cb.sec_pending_q) {
-            btm_cb.sec_pending_q = fixed_queue_new(SIZE_MAX);
+            btm_cb.sec_pending_q = fixed_queue_new(QUEUE_SIZE_MAX);
         }
 
         while ((p_e = (tBTM_SEC_QUEUE_ENTRY *)fixed_queue_try_dequeue(bq)) != NULL) {
@@ -4018,7 +4018,6 @@ void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable)
 #if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
     tACL_CONN       *p_acl = NULL;
     UINT8           acl_idx = btm_handle_to_acl_index(handle);
-    tGATT_TCB       *p_tcb = NULL;
 #endif
     BTM_TRACE_EVENT ("Security Manager: encrypt_change status:%d State:%d, encr_enable = %d\n",
                      status, (p_dev_rec) ? p_dev_rec->sec_state : 0, encr_enable);
@@ -4046,14 +4045,6 @@ void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable)
                 p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
             }
         } else {
-#if BLE_INCLUDED == TRUE
-            /* Before the application layer has received the connection event, the device has received an 
-            encrypted request from the peer device. The device should wait until the application layer 
-            receives the connection event before updating 'sec_flags'. */
-            if ((p_tcb = gatt_find_tcb_by_addr(p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE)) == NULL) {
-               //do nothing
-            } else
-#endif
             p_dev_rec->sec_flags |= (BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED);
         }
     }
@@ -4543,7 +4534,7 @@ void btm_sec_disconnected (UINT16 handle, UINT8 reason)
     if (!p_dev_rec) {
         return;
     }
-
+    p_dev_rec->enc_init_by_we = FALSE;
     transport  = (handle == p_dev_rec->hci_handle) ? BT_TRANSPORT_BR_EDR : BT_TRANSPORT_LE;
 
     p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
index 0af1006f8d1f42fae09996bcf0c3cadd0bd7537e..1dcaac45080d77dc7edd3fbc26edf02929673bde 100644 (file)
@@ -618,7 +618,7 @@ typedef struct {
 // btla-specific --
 #define BTM_SEC_NO_LAST_SERVICE_ID      0
     UINT8           last_author_service_id;         /* ID of last serviced authorized: Reset after each l2cap connection */
-
+    BOOLEAN         enc_init_by_we;
 } tBTM_SEC_DEV_REC;
 
 #define BTM_SEC_IS_SM4(sm) ((BOOLEAN)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE)))
index bf04bd14ddf517be6b35502d584fe716b4a06b05..7014cfde00ba188a5624b39e504e9170e413c6cc 100644 (file)
@@ -236,3 +236,13 @@ UINT16 BTU_BleAclPktSize(void)
     return 0;
 #endif
 }
+#if SCAN_QUEUE_CONGEST_CHECK
+bool BTU_check_queue_is_congest(void)
+{
+    UBaseType_t wait_size = uxQueueMessagesWaiting(xBtuQueue);
+    if(wait_size >= QUEUE_CONGEST_SIZE ) {
+        return true;
+    }
+    return false;
+}
+#endif
index ecb7b726f5510e3243c2d35d84fbb3cc54a0efdf..671ffa7427ba3b9dc52d0e07d2dbe9ec81e8cb2f 100644 (file)
@@ -1120,8 +1120,8 @@ static tGAP_CCB *gap_allocate_ccb (void)
     for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) {
         if (p_ccb->con_state == GAP_CCB_STATE_IDLE) {
             memset (p_ccb, 0, sizeof (tGAP_CCB));
-            p_ccb->tx_queue = fixed_queue_new(SIZE_MAX);
-            p_ccb->rx_queue = fixed_queue_new(SIZE_MAX);
+            p_ccb->tx_queue = fixed_queue_new(QUEUE_SIZE_MAX);
+            p_ccb->rx_queue = fixed_queue_new(QUEUE_SIZE_MAX);
 
             p_ccb->gap_handle   = xx;
             p_ccb->rem_mtu_size = L2CAP_MTU_SIZE;
index 0a3a104a4b8cc0480a179e1bf79e18b9c1941d83..46c5104c8339a05a7dc199f45c1f6d44aa52730b 100644 (file)
@@ -64,7 +64,7 @@ BOOLEAN gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID *p_service,  BOOLEAN
                                UINT16 s_hdl, UINT16 num_handle)
 {
     if (p_db->svc_buffer == NULL) { //in case already alloc
-        p_db->svc_buffer = fixed_queue_new(SIZE_MAX);
+        p_db->svc_buffer = fixed_queue_new(QUEUE_SIZE_MAX);
     }
 
     if (!allocate_svc_db_buf(p_db)) {
index 20f1988dee1a78a5908d9e7ee9d59163aa9d1458..add39455fe4c44b97213e4dd943e9eb1b8d58e08 100644 (file)
@@ -108,9 +108,9 @@ void gatt_init (void)
     gatt_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
 #endif
     gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE;
-    gatt_cb.sign_op_queue = fixed_queue_new(SIZE_MAX);
-    gatt_cb.srv_chg_clt_q = fixed_queue_new(SIZE_MAX);
-    gatt_cb.pending_new_srv_start_q = fixed_queue_new(SIZE_MAX);
+    gatt_cb.sign_op_queue = fixed_queue_new(QUEUE_SIZE_MAX);
+    gatt_cb.srv_chg_clt_q = fixed_queue_new(QUEUE_SIZE_MAX);
+    gatt_cb.pending_new_srv_start_q = fixed_queue_new(QUEUE_SIZE_MAX);
     /* First, register fixed L2CAP channel for ATT over BLE */
     fixed_reg.fixed_chnl_opts.mode         = L2CAP_FCR_BASIC_MODE;
     fixed_reg.fixed_chnl_opts.max_transmit = 0xFF;
index 697540d4c16ed2fcc776fb635d7d380555f0f85a..24df5a4eb3111c2f1dcba762e19c75f6623b2885 100644 (file)
@@ -167,7 +167,7 @@ static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status,
     GATT_TRACE_DEBUG ("process_read_multi_rsp status=%d mtu=%d", status, mtu);
 
        if (p_cmd->multi_rsp_q == NULL) {
-        p_cmd->multi_rsp_q = fixed_queue_new(SIZE_MAX);
+        p_cmd->multi_rsp_q = fixed_queue_new(QUEUE_SIZE_MAX);
        }
 
     /* Enqueue the response */
@@ -1290,7 +1290,7 @@ void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 hand
             queue_data->offset = offset;
             memcpy(queue_data->value, p, len);
             if (prepare_record->queue == NULL) {
-                prepare_record->queue = fixed_queue_new(SIZE_MAX);
+                prepare_record->queue = fixed_queue_new(QUEUE_SIZE_MAX);
             }
             fixed_queue_enqueue(prepare_record->queue, queue_data);
         }
index 95efcf6763eda974943a5a4f073dbb6b54047486..12a2e1dba324db38180fccefdecb570d877792a9 100644 (file)
@@ -337,7 +337,7 @@ tGATT_HDL_LIST_ELEM *gatt_alloc_hdl_buffer(void)
         if (!p_cb->hdl_list[i].in_use) {
             memset(p_elem, 0, sizeof(tGATT_HDL_LIST_ELEM));
             p_elem->in_use = TRUE;
-            p_elem->svc_db.svc_buffer = fixed_queue_new(SIZE_MAX);
+            p_elem->svc_db.svc_buffer = fixed_queue_new(QUEUE_SIZE_MAX);
             return p_elem;
         }
     }
@@ -1007,8 +1007,8 @@ tGATT_TCB *gatt_allocate_tcb_by_bdaddr(BD_ADDR bda, tBT_TRANSPORT transport)
 
         if (allocated) {
             memset(p_tcb, 0, sizeof(tGATT_TCB));
-            p_tcb->pending_enc_clcb = fixed_queue_new(SIZE_MAX);
-            p_tcb->pending_ind_q = fixed_queue_new(SIZE_MAX);
+            p_tcb->pending_enc_clcb = fixed_queue_new(QUEUE_SIZE_MAX);
+            p_tcb->pending_ind_q = fixed_queue_new(QUEUE_SIZE_MAX);
             p_tcb->in_use = TRUE;
             p_tcb->tcb_idx = i;
             p_tcb->transport = transport;
index 7c7404e2a4c0afc24532fec1fb0f7afab8af0e6d..5637cac6471212342efa1b79dfa93bfc52723abf 100644 (file)
@@ -1887,7 +1887,7 @@ BOOLEAN L2CA_RemoveFixedChnl (UINT16 fixed_cid, BD_ADDR rem_bda)
     p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport);
 
     if ( ((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) ) {
-        L2CAP_TRACE_WARNING ("L2CA_RemoveFixedChnl()  CID: 0x%04x  BDA: %08x%04x not connected", fixed_cid,
+        L2CAP_TRACE_DEBUG ("L2CA_RemoveFixedChnl()  CID: 0x%04x  BDA: %08x%04x not connected", fixed_cid,
                              (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3], (rem_bda[4] << 8) + rem_bda[5]);
         return (FALSE);
     }
index cacdcc6f50053ee67ae00b9c4e0b9a27e898e149..33bd0faf8d29fb9711e22a7aa02d03a962e42b0a 100644 (file)
@@ -750,7 +750,7 @@ void l2c_fcr_proc_pdu (tL2C_CCB *p_ccb, BT_HDR *p_buf)
     if ( (!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.srej_sent) &&
          (!fixed_queue_is_empty(p_ccb->fcrb.srej_rcv_hold_q))) {
         fixed_queue_t *temp_q = p_ccb->fcrb.srej_rcv_hold_q;
-        p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(SIZE_MAX);
+        p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(QUEUE_SIZE_MAX);
 
         while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(temp_q)) != NULL) {
             if (p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN)) {
index b1cfbe46ddbaeaaeb325d2ce11880f3c5bb88c7e..978e020e6501d01bc66880252c483e96f307a6f5 100644 (file)
@@ -74,7 +74,7 @@ tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, BOOLEAN is_bonding, tBT_TRANSPOR
 #if (BLE_INCLUDED == TRUE)
             p_lcb->transport       = transport;
             p_lcb->tx_data_len     = controller_get_interface()->get_ble_default_data_packet_length();
-            p_lcb->le_sec_pending_q = fixed_queue_new(SIZE_MAX);
+            p_lcb->le_sec_pending_q = fixed_queue_new(QUEUE_SIZE_MAX);
 
             if (transport == BT_TRANSPORT_LE) {
                 l2cb.num_ble_links_active++;
@@ -1519,11 +1519,11 @@ tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid)
     p_ccb->max_rx_mtu                = L2CAP_MTU_SIZE;
     p_ccb->tx_mps                    = L2CAP_FCR_TX_BUF_SIZE - 32;
 
-    p_ccb->xmit_hold_q  = fixed_queue_new(SIZE_MAX);
+    p_ccb->xmit_hold_q  = fixed_queue_new(QUEUE_SIZE_MAX);
 #if (CLASSIC_BT_INCLUDED == TRUE)
-    p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(SIZE_MAX);
-    p_ccb->fcrb.retrans_q = fixed_queue_new(SIZE_MAX);
-    p_ccb->fcrb.waiting_for_ack_q = fixed_queue_new(SIZE_MAX);
+    p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(QUEUE_SIZE_MAX);
+    p_ccb->fcrb.retrans_q = fixed_queue_new(QUEUE_SIZE_MAX);
+    p_ccb->fcrb.waiting_for_ack_q = fixed_queue_new(QUEUE_SIZE_MAX);
 #endif  ///CLASSIC_BT_INCLUDED == TRUE
 
     p_ccb->cong_sent    = FALSE;
index a88ae016f874cf8d474c8e4d3c6c1be2954b9921..0da8b3d76b7318dd176b025d9f0e206db18ca7d1 100644 (file)
@@ -128,8 +128,8 @@ void port_set_defaults (tPORT *p_port)
     memset (&p_port->rx, 0, sizeof (p_port->rx));
     memset (&p_port->tx, 0, sizeof (p_port->tx));
 
-    p_port->tx.queue = fixed_queue_new(SIZE_MAX);
-    p_port->rx.queue = fixed_queue_new(SIZE_MAX);
+    p_port->tx.queue = fixed_queue_new(QUEUE_SIZE_MAX);
+    p_port->rx.queue = fixed_queue_new(QUEUE_SIZE_MAX);
 }
 
 /*******************************************************************************
index 180632c04849c65538fede25e25c26c4a31ea763..8b1e0431166d752365708ee8442fe717850e7b88 100644 (file)
@@ -175,7 +175,7 @@ tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, BOOLEAN is_initiator)
             RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d, create new p_mcb:%p, index:%d",
                                is_initiator, &rfc_cb.port.rfc_mcb[j], j);
 
-            p_mcb->cmd_q = fixed_queue_new(SIZE_MAX);
+            p_mcb->cmd_q = fixed_queue_new(QUEUE_SIZE_MAX);
 
             p_mcb->is_initiator = is_initiator;
 
index 029a79ff1604677715c828a5618703467005a4f9..f91d6056b2842ea62219a28e8614b262567105d0 100644 (file)
@@ -58,6 +58,8 @@ extern elliptic_curve_t curve_p256;
 
 void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength);
 
+bool ECC_CheckPointIsInElliCur_P256(Point *p);
+
 #define ECC_PointMult(q, p, n, keyLength)  ECC_PointMult_Bin_NAF(q, p, n, keyLength)
 
 void p_256_init_curve(UINT32 keyLength);
index 991b6fd75756531791ca0115c0dc7510ad56dfe8..0f7ab3ec4143e5cd31f37d1e4822553dcad97024 100644 (file)
@@ -240,4 +240,40 @@ void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength)
     multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
 }
 
+bool ECC_CheckPointIsInElliCur_P256(Point *p)
+{
+    /* y^2 % q */
+    DWORD y_y_q[KEY_LENGTH_DWORDS_P256] = {0x0};
+    /* x^2 % q */
+    DWORD x_x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
+    /* x % q */
+    DWORD x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
+    /* x^2, To prevent overflow, the length of the x square here needs to 
+       be expanded to two times the original one. */
+    DWORD x_x[2*KEY_LENGTH_DWORDS_P256] = {0x0};
+    /* y_y_q =(p->y)^2(mod q) */
+    multiprecision_mersenns_squa_mod(y_y_q, p->y, KEY_LENGTH_DWORDS_P256);
+    /* Calculate the value of p->x square, x_x = (p->x)^2 */
+    multiprecision_mult(x_x, p->x, p->x, KEY_LENGTH_DWORDS_P256);
+    /* The function of the elliptic curve is y^2 = x^3 - 3x + b (mod q) ==>
+       y^2 = (x^2 - 3)*x + b (mod q),
+       so we calculate the x^2 - 3 value here */
+    x_x[0] -= 3;
+    /* Using math relations. (a*b) % q = ((a%q)*(b%q)) % q ==> 
+      (x^2 - 3)*x = (((x^2 - 3) % q) * x % q) % q */
+    multiprecision_fast_mod_P256(x_x_q, x_x);
+    /* x_x = x_x_q * x_q */
+    multiprecision_mult(x_x, x_x_q, p->x, KEY_LENGTH_DWORDS_P256);
+    /* x_q = x_x % q */
+    multiprecision_fast_mod_P256(x_q, x_x);
+    /* Save the result in x_x_q */
+    multiprecision_add_mod(x_x_q, x_q, curve_p256.b, KEY_LENGTH_DWORDS_P256);
+    /* compare the y_y_q and x_x_q, see if they are on a given elliptic curve. */
+    if (multiprecision_compare(y_y_q, x_x_q, KEY_LENGTH_DWORDS_P256)) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
 
index 0b5d50be2eb600011105a9abe2579317127400d0..bf3fe7def6ac7b63f2be028dd49fef3f4d8a8c77 100644 (file)
@@ -22,6 +22,7 @@
 #include "btm_int.h"
 #include "stack/l2c_api.h"
 #include "smp_int.h"
+#include "p_256_ecc_pp.h"
 //#include "utils/include/bt_utils.h"
 
 #if SMP_INCLUDED == TRUE
@@ -668,6 +669,12 @@ void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
 
     STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
     STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
+    /* In order to prevent the x and y coordinates of the public key from being modified, 
+       we need to check whether the x and y coordinates are on the given elliptic curve. */
+    if (!ECC_CheckPointIsInElliCur_P256((Point *)&p_cb->peer_publ_key)) {
+        SMP_TRACE_ERROR("%s, Invalid Public key.", __func__);
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    }
     p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
 
     smp_wait_for_both_public_keys(p_cb, NULL);
@@ -1831,7 +1838,7 @@ void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
 void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable)
 {
     tSMP_CB *p_cb = &smp_cb;
-
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (bda);
     SMP_TRACE_DEBUG("%s encr_enable=%d\n", __func__, encr_enable);
 
     if (memcmp(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN) == 0) {
@@ -1842,6 +1849,18 @@ void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable)
             btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size);
         }
 
+        smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
+    } 
+    else if(p_dev_rec && !p_dev_rec->enc_init_by_we){ 
+
+        /* 
+        if enc_init_by_we is false, it means that client initiates encryption before slave calls esp_ble_set_encryption()
+        we need initiate pairing_bda and p_cb->role then encryption, for example iPhones
+        */
+        memcpy(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN);
+        p_cb->state = SMP_STATE_ENCRYPTION_PENDING;
+        p_cb->role = HCI_ROLE_SLAVE;
+        p_dev_rec->enc_init_by_we = FALSE;
         smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
     }
 }
index 48feb8c015a8d6de8bef92fe2131b00704448094..12ca8e3cfe3be64ebfd5eb8100e63b1fd36c7906 100644 (file)
@@ -149,6 +149,11 @@ static btdm_dram_available_region_t btdm_dram_available_region[] = {
     {ESP_BT_MODE_BTDM,          0x3ffbdb28, 0x3ffc0000},
 };
 
+/* Reserve the full memory region used by Bluetooth Controller,
+   some may be released later at runtime. */
+SOC_RESERVE_MEMORY_REGION(0x3ffb0000, 0x3ffc0000, bt_hardware_shared_mem);
+SOC_RESERVE_MEMORY_REGION(0x3ffae6e0, 0x3ffaff10, rom_bt_data);
+
 #if CONFIG_SPIRAM_USE_MALLOC
 typedef struct {
     QueueHandle_t handle;
index 686982e157874e0e4d8aeb4d111f2bb6c437f5fd..d3c834d66153b1acd6b4e5e744a66aaa55ae5c40 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 686982e157874e0e4d8aeb4d111f2bb6c437f5fd
+Subproject commit d3c834d66153b1acd6b4e5e744a66aaa55ae5c40
diff --git a/components/bt/test/component.mk b/components/bt/test/component.mk
new file mode 100644 (file)
index 0000000..5dd172b
--- /dev/null
@@ -0,0 +1,5 @@
+#
+#Component Makefile
+#
+
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
diff --git a/components/bt/test/test_smp.c b/components/bt/test/test_smp.c
new file mode 100644 (file)
index 0000000..8758f9c
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ Tests for the BLE SMP implementation
+*/
+
+#include <esp_types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <string.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "unity.h"
+#include "esp_heap_caps.h"
+#include "esp_log.h"
+#include "freertos/ringbuf.h"
+#include "esp_system.h"
+#include "nvs_flash.h"
+
+#include "esp_bt.h"
+#include "esp_bt_main.h"
+#include "esp_bt_device.h"
+#include "esp_gap_ble_api.h"
+
+#define TAG "ble_smp_test"
+
+#define KEY_LENGTH_DWORDS_P256 8
+
+typedef unsigned long  DWORD;
+typedef uint32_t UINT32;
+
+typedef struct {
+DWORD x[KEY_LENGTH_DWORDS_P256];
+    DWORD y[KEY_LENGTH_DWORDS_P256];
+    DWORD z[KEY_LENGTH_DWORDS_P256];
+} Point;
+
+typedef struct {
+    // curve's coefficients
+    DWORD a[KEY_LENGTH_DWORDS_P256];
+    DWORD b[KEY_LENGTH_DWORDS_P256];
+
+    //whether a is -3
+    int a_minus3;
+
+    // prime modulus
+    DWORD p[KEY_LENGTH_DWORDS_P256];
+
+    // Omega, p = 2^m -omega
+    DWORD omega[KEY_LENGTH_DWORDS_P256];
+
+    // base point, a point on E of order r
+    Point G;
+
+} elliptic_curve_t;
+
+extern void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength);
+extern bool ECC_CheckPointIsInElliCur_P256(Point *p);
+extern void p_256_init_curve(UINT32 keyLength);
+extern elliptic_curve_t curve_p256;
+
+static void bt_rand(void *buf, size_t len)
+{
+    if (!len) {
+        return;
+    }
+    // Reset the buf value to the fixed value.
+    memset(buf, 0x55, len);
+
+    for (int i = 0; i < (int)(len / sizeof(uint32_t)); i++) {
+        uint32_t rand = esp_random();
+        memcpy(buf + i*sizeof(uint32_t), &rand, sizeof(uint32_t));
+    }
+
+    return;
+}
+
+TEST_CASE("ble_smp_public_key_check", "[ble_smp]")
+{
+    /* We wait init finish 200ms here */
+    vTaskDelay(200 / portTICK_PERIOD_MS);
+    Point public_key;
+    DWORD private_key[KEY_LENGTH_DWORDS_P256] = {[0 ... (KEY_LENGTH_DWORDS_P256 - 1)] = 0x12345678};
+    p_256_init_curve(KEY_LENGTH_DWORDS_P256);
+    ECC_PointMult_Bin_NAF(&public_key, &(curve_p256.G), private_key, KEY_LENGTH_DWORDS_P256);
+    /* Check Is the public key generated by the system on the given elliptic curve */
+    TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&public_key));
+    /* We simulate the attacker and set the y coordinate of the public key to 0. */
+    for (int i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
+        public_key.y[i] = 0x0;
+    }
+    /* At this point the public key should not be on the given elliptic curve. */
+    TEST_ASSERT(!ECC_CheckPointIsInElliCur_P256(&public_key));
+    /* Test whether the G point on the protocol is on a given elliptic curve */
+    TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&(curve_p256.G)));
+    /* test 100 times when the private key is generated by the random number. */
+    for (int j = 0; j < 100; j++) {
+        bt_rand(private_key, sizeof(DWORD)*KEY_LENGTH_DWORDS_P256);
+        ECC_PointMult_Bin_NAF(&public_key, &(curve_p256.G), private_key, KEY_LENGTH_DWORDS_P256);
+        /* Check Is the public key generated by the system on the given elliptic curve */
+        TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&public_key));
+    }
+}
index 07bf6988539d76c07f85d8ba087ef96e2a7faa08..d81d2c25c316e0c8933c40ed67d707b112e500ae 100644 (file)
@@ -316,7 +316,7 @@ esp_err_t gpio_reset_pin(gpio_num_t gpio_num)
 {
     assert(gpio_num >= 0 && GPIO_IS_VALID_GPIO(gpio_num));
     gpio_config_t cfg = {
-        .pin_bit_mask = BIT(gpio_num),
+        .pin_bit_mask = BIT64(gpio_num),
         .mode = GPIO_MODE_DISABLE,
         //for powersave reasons, the GPIO should not be floating, select pullup
         .pull_up_en = true,
index 6f0fd2d72acbfcbee085044a7100e61828917412..21e2e2ec7c40948d4348a7b11328a22c6e770ff3 100644 (file)
@@ -122,6 +122,7 @@ esp_err_t touch_pad_init();
 
 /**
  * @brief Un-install touch pad driver.
+ * @note  After this function is called, other touch functions are prohibited from being called.
  * @return
  *     - ESP_OK   Success
  *     - ESP_FAIL Touch pad driver not initialized
index 2cf891ae3d20bb0d3894120d308fa7d05df799fe..f7f63100af31c7eebbf887fdf71b28ae6b6f07b3 100644 (file)
@@ -1,6 +1,9 @@
+// Copyright 2016-2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
-
+//
 //     http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
@@ -476,7 +479,7 @@ static void touch_pad_filter_cb(void *arg)
 {
     static uint32_t s_filtered_temp[TOUCH_PAD_MAX] = {0};
 
-    if (s_touch_pad_filter == NULL) {
+    if (s_touch_pad_filter == NULL || rtc_touch_mux == NULL) {
         return;
     }
     uint16_t val = 0;
@@ -825,14 +828,17 @@ esp_err_t touch_pad_init()
 
 esp_err_t touch_pad_deinit()
 {
-    if (rtc_touch_mux == NULL) {
-        return ESP_FAIL;
+    RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_FAIL);
+    if (s_touch_pad_filter != NULL) {
+        touch_pad_filter_stop();
+        touch_pad_filter_delete();
     }
+    xSemaphoreTake(rtc_touch_mux, portMAX_DELAY);
     s_touch_pad_init_bit = 0x0000;
-    touch_pad_filter_delete();
     touch_pad_set_fsm_mode(TOUCH_FSM_MODE_SW);
     touch_pad_clear_status();
     touch_pad_intr_disable();
+    xSemaphoreGive(rtc_touch_mux);
     vSemaphoreDelete(rtc_touch_mux);
     rtc_touch_mux = NULL;
     return ESP_OK;
@@ -972,7 +978,7 @@ esp_err_t touch_pad_filter_start(uint32_t filter_period_ms)
 esp_err_t touch_pad_filter_stop()
 {
     RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE);
-
+    RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_ERR_INVALID_STATE);
     esp_err_t ret = ESP_OK;
     xSemaphoreTake(rtc_touch_mux, portMAX_DELAY);
     if (s_touch_pad_filter != NULL) {
@@ -988,6 +994,7 @@ esp_err_t touch_pad_filter_stop()
 esp_err_t touch_pad_filter_delete()
 {
     RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE);
+    RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_ERR_INVALID_STATE);
     xSemaphoreTake(rtc_touch_mux, portMAX_DELAY);
     if (s_touch_pad_filter != NULL) {
         if (s_touch_pad_filter->timer != NULL) {
index 815f5c79a9d75d40774fb83b81f1eed83b631889..ec6e2ff4f60bb23df4e4e5520a8d30f40293a11b 100644 (file)
@@ -56,8 +56,8 @@ TEST_CASE("adc2 work with wifi","[adc]")
     //init wifi
     printf("nvs init\n");
     esp_err_t r = nvs_flash_init();
-    if (r == ESP_ERR_NVS_NO_FREE_PAGES) {
-        printf("no free pages, erase..\n");
+    if (r == ESP_ERR_NVS_NO_FREE_PAGES || r == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        printf("no free pages or nvs version mismatch, erase..\n");
         TEST_ESP_OK(nvs_flash_erase());
         r = nvs_flash_init();
     } 
index 5a7b49010936363c34698c1a8283573ff33ecbca..8887d5cefc17a2394fe2e0c3b1727adddf3e4792 100644 (file)
@@ -22,6 +22,7 @@
 #include "soc/spi_periph.h"
 #include "freertos/ringbuf.h"
 #include "soc/gpio_periph.h"
+#include "sdkconfig.h"
 
 const static char TAG[] = "test_spi";
 
@@ -118,7 +119,7 @@ TEST_CASE("SPI Master clockdiv calculation routines", "[spi]")
 
 static spi_device_handle_t setup_spi_bus(int clkspeed, bool dma) {
     spi_bus_config_t buscfg={
-        .mosi_io_num=4,
+        .mosi_io_num=26,
         .miso_io_num=26,
         .sclk_io_num=25,
         .quadwp_io_num=-1,
@@ -137,22 +138,24 @@ static spi_device_handle_t setup_spi_bus(int clkspeed, bool dma) {
     };
     esp_err_t ret;
     spi_device_handle_t handle;
-    printf("THIS TEST NEEDS A JUMPER BETWEEN IO4 AND IO26\n");
 
     ret=spi_bus_initialize(HSPI_HOST, &buscfg, dma?1:0);
     TEST_ASSERT(ret==ESP_OK);
     ret=spi_bus_add_device(HSPI_HOST, &devcfg, &handle);
     TEST_ASSERT(ret==ESP_OK);
+    //connect MOSI to two devices breaks the output, fix it.
+    gpio_output_sel(26, FUNC_GPIO, HSPID_OUT_IDX);
     printf("Bus/dev inited.\n");
     return handle;
 }
 
-static void spi_test(spi_device_handle_t handle, int num_bytes) {
+static int spi_test(spi_device_handle_t handle, int num_bytes) {
     esp_err_t ret;
     int x;
+    bool success = true;
     srand(num_bytes);
-    char *sendbuf=heap_caps_malloc(num_bytes, MALLOC_CAP_DMA);
-    char *recvbuf=heap_caps_malloc(num_bytes, MALLOC_CAP_DMA);
+    char *sendbuf=heap_caps_malloc((num_bytes+3)&(~3), MALLOC_CAP_DMA);
+    char *recvbuf=heap_caps_malloc((num_bytes+3)&(~3), MALLOC_CAP_DMA);
     for (x=0; x<num_bytes; x++) {
         sendbuf[x]=rand()&0xff;
         recvbuf[x]=0x55;
@@ -181,6 +184,7 @@ static void spi_test(spi_device_handle_t handle, int num_bytes) {
     if (x!=num_bytes) {
         int from=x-16;
         if (from<0) from=0;
+        success = false;
         printf("Error at %d! Sent vs recved: (starting from %d)\n" , x, from);
         for (int i=0; i<32; i++) {
             if (i+from<num_bytes) printf("%02X ", sendbuf[from+i]);
@@ -190,13 +194,12 @@ static void spi_test(spi_device_handle_t handle, int num_bytes) {
             if (i+from<num_bytes) printf("%02X ", recvbuf[from+i]);
         }
         printf("\n");
-//        TEST_ASSERT(0);
     }
 
-    printf("Success!\n");
-
+    if (success) printf("Success!\n");
     free(sendbuf);
     free(recvbuf);
+    return success;
 }
 
 static void destroy_spi_bus(spi_device_handle_t handle) {
@@ -210,26 +213,27 @@ static void destroy_spi_bus(spi_device_handle_t handle) {
 
 #define TEST_LEN 111
 
-TEST_CASE("SPI Master test", "[spi][ignore]")
+TEST_CASE("SPI Master test", "[spi]")
 {
+    bool success = true;
     printf("Testing bus at 80KHz\n");
     spi_device_handle_t handle=setup_spi_bus(80000, true);
-    spi_test(handle, 16); //small
-    spi_test(handle, 21); //small, unaligned
-    spi_test(handle, 36); //aligned
-    spi_test(handle, 128); //aligned
-    spi_test(handle, 129); //unaligned
-    spi_test(handle, 4096-2); //multiple descs, edge case 1
-    spi_test(handle, 4096-1); //multiple descs, edge case 2
-    spi_test(handle, 4096*3); //multiple descs
+    success &= spi_test(handle, 16); //small
+    success &= spi_test(handle, 21); //small, unaligned
+    success &= spi_test(handle, 36); //aligned
+    success &= spi_test(handle, 128); //aligned
+    success &= spi_test(handle, 129); //unaligned
+    success &= spi_test(handle, 4096-2); //multiple descs, edge case 1
+    success &= spi_test(handle, 4096-1); //multiple descs, edge case 2
+    success &= spi_test(handle, 4096*3); //multiple descs
 
     destroy_spi_bus(handle);
 
     printf("Testing bus at 80KHz, non-DMA\n");
     handle=setup_spi_bus(80000, false);
-    spi_test(handle, 4); //aligned
-    spi_test(handle, 16); //small
-    spi_test(handle, 21); //small, unaligned
+    success &= spi_test(handle, 4); //aligned
+    success &= spi_test(handle, 16); //small
+    success &= spi_test(handle, 21); //small, unaligned
 
     destroy_spi_bus(handle);
 
@@ -237,21 +241,23 @@ TEST_CASE("SPI Master test", "[spi][ignore]")
     printf("Testing bus at 26MHz\n");
     handle=setup_spi_bus(20000000, true);
 
-    spi_test(handle, 128); //DMA, aligned
-    spi_test(handle, 4096*3); //DMA, multiple descs
+    success &= spi_test(handle, 128); //DMA, aligned
+    success &= spi_test(handle, 4096*3); //DMA, multiple descs
     destroy_spi_bus(handle);
 
     printf("Testing bus at 900KHz\n");
     handle=setup_spi_bus(9000000, true);
 
-    spi_test(handle, 128); //DMA, aligned
-    spi_test(handle, 4096*3); //DMA, multiple descs
+    success &= spi_test(handle, 128); //DMA, aligned
+    success &= spi_test(handle, 4096*3); //DMA, multiple descs
     destroy_spi_bus(handle);
+    TEST_ASSERT(success);
 }
 
 
-TEST_CASE("SPI Master test, interaction of multiple devs", "[spi][ignore]") {
+TEST_CASE("SPI Master test, interaction of multiple devs", "[spi]") {
     esp_err_t ret;
+    bool success = true;
     spi_device_interface_config_t devcfg={
         .command_bits=0,
         .address_bits=0,
@@ -267,28 +273,29 @@ TEST_CASE("SPI Master test, interaction of multiple devs", "[spi][ignore]") {
     spi_bus_add_device(HSPI_HOST, &devcfg, &handle2);
 
     printf("Sending to dev 1\n");
-    spi_test(handle1, 7);
+    success &= spi_test(handle1, 7);
     printf("Sending to dev 1\n");
-    spi_test(handle1, 15);
+    success &= spi_test(handle1, 15);
     printf("Sending to dev 2\n");
-    spi_test(handle2, 15);
+    success &= spi_test(handle2, 15);
     printf("Sending to dev 1\n");
-    spi_test(handle1, 32);
+    success &= spi_test(handle1, 32);
     printf("Sending to dev 2\n");
-    spi_test(handle2, 32);
+    success &= spi_test(handle2, 32);
     printf("Sending to dev 1\n");
-    spi_test(handle1, 63);
+    success &= spi_test(handle1, 63);
     printf("Sending to dev 2\n");
-    spi_test(handle2, 63);
+    success &= spi_test(handle2, 63);
     printf("Sending to dev 1\n");
-    spi_test(handle1, 5000);
+    success &= spi_test(handle1, 5000);
     printf("Sending to dev 2\n");
-    spi_test(handle2, 5000);
+    success &= spi_test(handle2, 5000);
 
 
     ret=spi_bus_remove_device(handle2);
     TEST_ASSERT(ret==ESP_OK);
     destroy_spi_bus(handle1);
+    TEST_ASSERT(success);
 }
 
 TEST_CASE("spi bus setting with different pin configs", "[spi]")
@@ -495,10 +502,21 @@ TEST_CASE("SPI Master no response when switch from host1 (HSPI) to host2 (VSPI)"
     TEST_ASSERT(spi_bus_free(host) == ESP_OK);
 }
 
-IRAM_ATTR  static uint32_t data_iram[320];
-DRAM_ATTR  static uint32_t data_dram[320]={0};
+IRAM_ATTR  static uint32_t data_iram[80];
+DRAM_ATTR  static uint32_t data_dram[80]={0};
 //force to place in code area.
-static const uint32_t data_drom[320] = {0};
+static const uint8_t data_drom[320+3] = {
+0xD8, 0xD1, 0x0A, 0xB8, 0xCE, 0x67, 0x1B, 0x11, 0x17, 0xA0, 0xDA, 0x89, 0x55, 0xC1, 0x40, 0x0F, 0x55, 0xEB, 0xF7, 0xEC, 0xF0, 0x3C, 0x0F, 0x4D, 0x2B, 0x9E, 0xBF, 0xCD, 0x57, 0x2C, 0x48, 0x1A,
+0x8B, 0x47, 0xC5, 0x01, 0x0C, 0x05, 0x80, 0x30, 0xF4, 0xEA, 0xE5, 0x92, 0x56, 0x97, 0x98, 0x78, 0x21, 0x34, 0xA1, 0xBC, 0xAE, 0x93, 0x7E, 0x96, 0x08, 0xE6, 0x54, 0x6A, 0x6C, 0x67, 0xCF, 0x58,
+0xEE, 0x15, 0xA8, 0xB6, 0x32, 0x8C, 0x85, 0xF7, 0xE9, 0x88, 0x5E, 0xB1, 0x76, 0xE4, 0xB2, 0xC7, 0x0F, 0x57, 0x51, 0x7A, 0x2F, 0xAB, 0x12, 0xC3, 0x37, 0x99, 0x4E, 0x67, 0x75, 0x28, 0xE4, 0x1D,
+0xF8, 0xBA, 0x22, 0xCB, 0xA1, 0x18, 0x4C, 0xAB, 0x5F, 0xC9, 0xF3, 0xA2, 0x39, 0x92, 0x44, 0xE6, 0x7B, 0xE3, 0xD0, 0x16, 0xC5, 0xC2, 0xCB, 0xD9, 0xC0, 0x7F, 0x06, 0xBF, 0x3E, 0xCE, 0xE1, 0x26,
+0xD5, 0x3C, 0xAD, 0x0E, 0xC1, 0xC7, 0x7D, 0x0D, 0x56, 0x85, 0x6F, 0x32, 0xC8, 0x63, 0x8D, 0x12, 0xAB, 0x1E, 0x81, 0x7B, 0xF4, 0xF1, 0xA9, 0xAF, 0xD9, 0x74, 0x60, 0x05, 0x3D, 0xCC, 0x0C, 0x34,
+0x11, 0x44, 0xAE, 0x2A, 0x13, 0x2F, 0x04, 0xC3, 0x59, 0xF0, 0x54, 0x07, 0xBA, 0x26, 0xD9, 0xFB, 0x80, 0x95, 0xC0, 0x14, 0xFA, 0x27, 0xEF, 0xD3, 0x58, 0xB8, 0xE4, 0xA2, 0xE3, 0x5E, 0x94, 0xB3,
+0xCD, 0x2C, 0x4F, 0xAC, 0x3B, 0xD1, 0xCA, 0xBE, 0x61, 0x71, 0x7B, 0x62, 0xEB, 0xF0, 0xFC, 0xEF, 0x22, 0xB7, 0x3F, 0x56, 0x65, 0x19, 0x61, 0x73, 0x1A, 0x4D, 0xE4, 0x23, 0xE5, 0x3A, 0x91, 0x5C,
+0xE6, 0x1B, 0x5F, 0x0E, 0x10, 0x94, 0x7C, 0x9F, 0xCF, 0x75, 0xB3, 0xEB, 0x42, 0x4C, 0xCF, 0xFE, 0xAF, 0x68, 0x62, 0x3F, 0x9A, 0x3C, 0x81, 0x3E, 0x7A, 0x45, 0x92, 0x79, 0x91, 0x4F, 0xFF, 0xDE,
+0x25, 0x18, 0x33, 0xB9, 0xA9, 0x3A, 0x3F, 0x1F, 0x4F, 0x4B, 0x5C, 0x71, 0x82, 0x75, 0xB0, 0x1F, 0xE9, 0x98, 0xA3, 0xE2, 0x65, 0xBB, 0xCA, 0x4F, 0xB7, 0x1D, 0x23, 0x43, 0x16, 0x73, 0xBD, 0x83,
+0x70, 0x22, 0x7D, 0x0A, 0x6D, 0xD3, 0x77, 0x73, 0xD0, 0xF4, 0x06, 0xB2, 0x19, 0x8C, 0xFF, 0x58, 0xE4, 0xDB, 0xE9, 0xEC, 0x89, 0x6A, 0xF4, 0x0E, 0x67, 0x12, 0xEC, 0x11, 0xD2, 0x1F, 0x8D, 0xD7,
+};
 
 #if 1 //HSPI
 #define PIN_NUM_MISO HSPI_IOMUX_PIN_NUM_MISO
@@ -518,77 +536,84 @@ static const uint32_t data_drom[320] = {0};
 
 TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]")
 {
-    uint32_t data_rxdram[320];
+#ifdef CONFIG_SPIRAM_SUPPORT
+    //test psram if enabled
+    ESP_LOGI(TAG, "testing PSRAM...");
+    uint32_t* data_malloc = (uint32_t*)heap_caps_calloc(1, 324, MALLOC_CAP_SPIRAM);
+#else
+    uint32_t* data_malloc = (uint32_t*)heap_caps_calloc(1, 324, MALLOC_CAP_DMA);
+#endif
+
+    TEST_ASSERT(data_malloc != NULL);
+
+    srand(52);
+    for (int i = 0; i < 320/4; i++) {
+        data_iram[i] = rand();
+        data_dram[i] = rand();
+        data_malloc[i] = rand();
+    }
 
     esp_err_t ret;
     spi_device_handle_t spi;
-    spi_bus_config_t buscfg={
-        .miso_io_num=PIN_NUM_MISO,
-        .mosi_io_num=PIN_NUM_MOSI,
-        .sclk_io_num=PIN_NUM_CLK,
-        .quadwp_io_num=-1,
-        .quadhd_io_num=-1
-    };
-    spi_device_interface_config_t devcfg={
-        .clock_speed_hz=10000000,               //Clock out at 10 MHz
-        .mode=0,                                //SPI mode 0
-        .spics_io_num=PIN_NUM_CS,               //CS pin
-        .queue_size=7,                          //We want to be able to queue 7 transactions at a time
-        .pre_cb=NULL,  //Specify pre-transfer callback to handle D/C line
-    };
+    spi_bus_config_t buscfg=SPI_BUS_TEST_DEFAULT_CONFIG();
+    buscfg.miso_io_num = PIN_NUM_MOSI;
+    spi_device_interface_config_t devcfg=SPI_DEVICE_TEST_DEFAULT_CONFIG();
+
     //Initialize the SPI bus
     ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
     TEST_ASSERT(ret==ESP_OK);
     //Attach the LCD to the SPI bus
     ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
     TEST_ASSERT(ret==ESP_OK);
+    //connect MOSI to two devices breaks the output, fix it.
+    gpio_output_sel(buscfg.mosi_io_num, FUNC_GPIO, HSPID_OUT_IDX);
 
-    static spi_transaction_t trans[6];
+#define TEST_REGION_SIZE 5
+    static spi_transaction_t trans[TEST_REGION_SIZE];
     int x;
 
-    printf("iram: %p, dram: %p, drom: %p\n", data_iram, data_dram, data_drom);
+    ESP_LOGI(TAG, "iram: %p, dram: %p", data_iram, data_dram);
+    ESP_LOGI(TAG, "drom: %p, malloc: %p", data_drom, data_malloc);
 
     memset(trans, 0, 6*sizeof(spi_transaction_t));
 
     trans[0].length = 320*8,
     trans[0].tx_buffer = data_iram;
-    trans[0].rx_buffer = data_rxdram;
+    trans[0].rx_buffer = data_malloc+1;
 
     trans[1].length = 320*8,
     trans[1].tx_buffer = data_dram;
-    trans[1].rx_buffer = data_rxdram;
+    trans[1].rx_buffer = data_iram;
 
     trans[2].length = 320*8,
-    trans[2].tx_buffer = data_drom;
-    trans[2].rx_buffer = data_rxdram;
+    trans[2].tx_buffer = data_malloc+2;
+    trans[2].rx_buffer = data_dram;
 
     trans[3].length = 320*8,
     trans[3].tx_buffer = data_drom;
     trans[3].rx_buffer = data_iram;
 
-    trans[4].length = 320*8,
-    trans[4].rxlength = 8*4;
-    trans[4].tx_buffer = data_drom;
-    trans[4].flags = SPI_TRANS_USE_RXDATA;
-
-    trans[5].length = 8*4;
-    trans[5].flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
+    trans[4].length = 4*8,
+    trans[4].flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
+    uint32_t* ptr = (uint32_t*)trans[4].rx_data;
+    *ptr = 0x54545454;
+    ptr = (uint32_t*)trans[4].tx_data;
+    *ptr = 0xbc124960;
 
     //Queue all transactions.
-    for (x=0; x<6; x++) {
-        ret=spi_device_queue_trans(spi,&trans[x], portMAX_DELAY);
-        TEST_ASSERT(ret==ESP_OK);
-    }
-
-    for (x=0; x<6; x++) {
-        spi_transaction_t* ptr;
-        ret=spi_device_get_trans_result(spi,&ptr, portMAX_DELAY);
+    for (x=0; x<TEST_REGION_SIZE; x++) {
+        ESP_LOGI(TAG, "transmitting %d...", x);
+        ret=spi_device_transmit(spi,&trans[x]);
         TEST_ASSERT(ret==ESP_OK);
-        TEST_ASSERT(ptr = trans+x);
+        if (trans[x].flags & SPI_TRANS_USE_RXDATA) {
+            TEST_ASSERT_EQUAL_HEX8_ARRAY(trans[x].tx_data, trans[x].rx_data, 4);
+        } else {
+            TEST_ASSERT_EQUAL_HEX32_ARRAY(trans[x].tx_buffer, trans[x].rx_buffer, trans[x].length / 8 /4);
+        }
     }
-
     TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
     TEST_ASSERT(spi_bus_free(HSPI_HOST) == ESP_OK);
+    free(data_malloc);
 }
 
 //this part tests 3 DMA issues in master mode, full-duplex in IDF2.1
index 4b93037b8a12a11af77cfac1cbfedfdb1e979fcd..b6154b2cc8874d016c9e24c34e47bde59cc3722f 100644 (file)
@@ -136,6 +136,23 @@ TEST_CASE("test uart get baud-rate","[uart]")
     ESP_LOGI(UART_TAG, "get baud-rate test passed  ....\n");
 }
 
+TEST_CASE("test uart tx data with break","[uart]")
+{
+    const int buf_len = 200;
+    const int send_len = 128;
+    const int brk_len = 10;
+    char *psend = (char *)malloc(buf_len);
+    TEST_ASSERT( psend != NULL);
+    memset(psend, '0', buf_len);
+    uart_config(UART_BAUD_115200, false);
+    printf("Uart%d send %d bytes with break\n", UART_NUM1, send_len);
+    uart_write_bytes_with_break(UART_NUM1, (const char *)psend, send_len, brk_len);
+    uart_wait_tx_done(UART_NUM1, (portTickType)portMAX_DELAY);
+    //If the code is running here, it means the test passed, otherwise it will crash due to the interrupt wdt timeout.
+    printf("Send data with break test passed\n");
+    free(psend);
+}
+
 // Calculate buffer checksum using tables 
 // The checksum CRC16 algorithm is specific
 // for Modbus standard and uses polynomial value = 0xA001
index b1b8ae78910925e260b5fe8f2051b27a48b9960c..876f4d027988cc4cec731cb6d469eed54baff810 100644 (file)
@@ -761,7 +761,6 @@ static void uart_rx_intr_handler_default(void *param)
                                 p_uart->tx_ptr = NULL;
                                 p_uart->tx_len_tot = p_uart->tx_head->tx_data.size;
                                 if(p_uart->tx_head->type == UART_DATA_BREAK) {
-                                    p_uart->tx_len_tot = p_uart->tx_head->tx_data.size;
                                     p_uart->tx_brk_flg = 1;
                                     p_uart->tx_brk_len = p_uart->tx_head->tx_data.brk_len;
                                 }
@@ -809,7 +808,7 @@ static void uart_rx_intr_handler_default(void *param)
                             p_uart->tx_ptr = NULL;
                             //Sending item done, now we need to send break if there is a record.
                             //Set TX break signal after FIFO is empty
-                            if(p_uart->tx_brk_flg == 1 && p_uart->tx_len_tot == 0) {
+                            if(p_uart->tx_len_tot == 0 && p_uart->tx_brk_flg == 1) {
                                 UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
                                 uart_reg->int_ena.tx_brk_done = 0;
                                 uart_reg->idle_conf.tx_brk_num = p_uart->tx_brk_len;
@@ -818,6 +817,8 @@ static void uart_rx_intr_handler_default(void *param)
                                 uart_reg->int_ena.tx_brk_done = 1;
                                 UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
                                 p_uart->tx_waiting_brk = 1;
+                                //do not enable TX empty interrupt
+                                en_tx_flg = false;
                             } else {
                                 //enable TX empty interrupt
                                 en_tx_flg = true;
index 56ce08b64a744d3927ef9aaa1ce7e47ef9044f1f..078afe93ba3998008512ecc4e8f47317df6223c2 100644 (file)
@@ -127,6 +127,10 @@ static void esp_core_dump_write(XtExcFrame *frame, core_dump_write_config_t *wri
         if (tasks[i].pxTCB == xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID())) {
             // set correct stack top for current task
             tasks[i].pxTopOfStack = (StackType_t *)frame;
+            // This field is not initialized for crashed task, but stack frame has the structure of interrupt one,
+            // so make workaround to allow espcoredump to parse it properly.
+            if (frame->exit == 0)
+                frame->exit = -1;
             ESP_COREDUMP_LOG_PROCESS("Current task EXIT/PC/PS/A0/SP %x %x %x %x %x",
                 frame->exit, frame->pc, frame->ps, frame->a0, frame->a1);
         }
index 01642432d87b2e8de36c9e67991f25c1bd06358c..bf044bd7b265dcacc6350346e03d20f268673fd3 100644 (file)
@@ -29,6 +29,7 @@
 #include "soc/io_mux_reg.h"
 #include "soc/rtc_cntl_reg.h"
 #include "soc/timer_group_reg.h"
+#include "soc/rtc_wdt.h"
 
 #include "driver/rtc_io.h"
 
@@ -136,7 +137,7 @@ void IRAM_ATTR call_start_cpu0()
         || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET
 #endif
     ) {
-        esp_panic_wdt_stop();
+        rtc_wdt_disable();
     }
 
     //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this.
@@ -428,7 +429,7 @@ static void main_task(void* args)
 {
     // Now that the application is about to start, disable boot watchdogs
     REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
-    REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
+    rtc_wdt_disable();
 #if !CONFIG_FREERTOS_UNICORE
     // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
     while (port_xSchedulerRunning[1] == 0) {
index 49de0e56d46d581fe34b50e08f0a0d5eac4d2fa4..7b74704e01fd075fc0a64e4af9de4653d3d9fa03 100644 (file)
@@ -160,6 +160,11 @@ static const esp_err_msg_t esp_err_msg_table[] = {
 #   ifdef      ESP_ERR_NVS_PART_NOT_FOUND
     ERR_TBL_IT(ESP_ERR_NVS_PART_NOT_FOUND),                 /*  4367 0x110f Partition with specified name is not found
                                                                             in the partition table */
+#   endif
+#   ifdef      ESP_ERR_NVS_NEW_VERSION_FOUND
+    ERR_TBL_IT(ESP_ERR_NVS_NEW_VERSION_FOUND),              /*  4368 0x1110 NVS partition contains data in new format
+                                                                            and cannot be recognized by this version of
+                                                                            code */
 #   endif
     // components/ulp/include/esp32/ulp.h
 #   ifdef      ESP_ERR_ULP_BASE
index db9cb1d1634049fa1c50d448b3a1fa11b91638d9..8fea167de14cb8a1ca24597c326a296837f7481b 100644 (file)
@@ -1312,6 +1312,14 @@ esp_err_t esp_mesh_scan_get_ap_ie_len(int *len);
  */
 esp_err_t esp_mesh_scan_get_ap_record(wifi_ap_record_t *ap_record, void *buffer);
 
+/**
+ * @brief     flush upstream packets pending in to_parent queue and to_parent_p2p queue
+ *
+ * @return
+ *    - ESP_OK
+ */
+esp_err_t esp_mesh_flush_upstream_packets(void);
+
 #ifdef __cplusplus
 }
 #endif
index 36bc2dc9045066940f9fa110855e55e55b4aa76f..5f73984a1a0b3ca513d96b145893e11150e8c62f 100644 (file)
@@ -33,24 +33,22 @@ extern "C" {
  *                Structures
  *******************************************************/
 typedef struct {
-    int scan;          /**< minimum scan times before being a root, default:10 */
-    int vote;          /**< max vote times in self-healing, default:10000 */
-    int fail;          /**< parent selection fail times, if the scan times reach this value,
-                            will disconnect with associated children and join self-healing. default:60 */
-    int monitor_ie;    /**< acceptable times of parent ie change before update self ie, default:3 */
+    int scan;          /**< minimum scan times before being a root, default:10. */
+    int vote;          /**< max vote times in self-healing, default:1000. */
+    int fail;          /**< parent selection fail times. If the scan times reach this value,
+                            device will disconnect with associated children and join self-healing, default:120. */
+    int monitor_ie;    /**< acceptable times of parent networking IE change before update self networking IE, default:10. */
 } mesh_attempts_t;
 
 typedef struct {
-    int duration_ms;   /* parent weak RSSI monitor duration, if the RSSI continues to be weak during this duration_ms,
-                          will switch to a better parent */
+    int duration_ms;   /* parent weak RSSI monitor duration. If the RSSI with current parent is less than cnx_rssi continuously
+                          within this duration_ms, device will search for a better parent. */
     int cnx_rssi;      /* RSSI threshold for keeping a good connection with parent.
-                          if set a value greater than -120 dBm, will arm a timer to monitor current RSSI at a period time of
-                          duration_ms. if keep the default value(-120 dBm), a timer at a random period(<3minutes) will
-                          be armed to switch a better parent if there does have one.
-                          The better parent must have RSSI greater than a high RSSI threshold(-78 dBm by default) and a top layer
-                          than current one. */
-    int select_rssi;   /* RSSI threshold for parent selection, should be a value greater than switch_rssi */
-    int switch_rssi;   /* Disassociate current parent and switch to a new parent when the RSSI is greater than this set threshold */
+                          If set a value greater than -120 dBm, device will arm a timer to monitor current RSSI at a period time of
+                          duration_ms. */
+    int select_rssi;   /* RSSI threshold for parent selection, should be a value greater than switch_rssi. */
+    int switch_rssi;   /* RSSI threshold for parent switch. Device will disassociate current parent and switch to a new parent when
+                          the RSSI with the new parent is greater than this set threshold. */
     int backoff_rssi;  /* RSSI threshold for connecting to the root */
 } mesh_switch_parent_t;
 
@@ -69,8 +67,8 @@ typedef struct {
     uint8_t len;             /**< element length */
     uint8_t oui[3];          /**< organization identifier */
     /**< mesh networking IE content */
-    uint8_t type;            /** mesh networking IE type */
-    uint8_t encryped : 1;    /**< if mesh networking IE is encrypted */
+    uint8_t type;            /** ESP defined IE type */
+    uint8_t encryped : 1;    /**< whether mesh networking IE is encrypted */
     uint8_t version : 7;     /**< mesh networking IE version */
     /**< content */
     uint8_t mesh_type;       /**< mesh device type */
@@ -126,9 +124,9 @@ esp_err_t esp_mesh_set_beacon_interval(int interval_ms);
 esp_err_t esp_mesh_get_beacon_interval(int *interval_ms);
 
 /**
- * @brief    set attempts for mesh self-organized networking
+ * @brief     set attempts for mesh self-organized networking
  *
- * @param    attempts
+ * @param     attempts
  *
  * @return
  *    - ESP_OK
index 4e0630a24581031c514d2a109d6504a6875b2c28..b9e192f04629b062e5e438a4b0b93409895ece94 100644 (file)
@@ -61,12 +61,6 @@ esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags);
  */
 void esp_clear_watchpoint(int no);
 
-
-/**
- * @brief Stops panic WDT
- */
-void esp_panic_wdt_stop(void);
-
 /**
  * @brief Checks stack pointer
  */
index 9663dcddcbd35659bb43c1c305460efd1f6e8c7d..aafd85cee88dde48175b9da80775dd4744d8d522 100644 (file)
 
 #include <stddef.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include "esp_err.h"
 
+typedef enum {
+    ESP_SPIRAM_VOLT_3V3 = 0,       /*!< SPI RAM voltage is 3.3v */
+    ESP_SPIRAM_VOLT_1V8 = 1,       /*!< SPI RAM voltage is 1.8v */
+    ESP_SPIRAM_VOLT_INVALID,       /*!< SPI RAM voltage is invalid*/
+} esp_spiram_volt_t;
+
+typedef enum {
+    ESP_SPIRAM_SIZE_32MBITS = 0,   /*!< SPI RAM size is 32 MBits */
+    ESP_SPIRAM_SIZE_64MBITS = 1,   /*!< SPI RAM size is 64 MBits */
+    ESP_SPIRAM_SIZE_INVALID,       /*!< SPI RAM size is invalid */
+} esp_spiram_size_t;
+
+/**
+ * @brief get SPI RAM voltage
+ * @return
+ *     - ESP_SPIRAM_VOLT_INVALID if SPI RAM not enabled or not valid.
+ *     - SPI RAM voltage
+ */
+esp_spiram_volt_t esp_spiram_get_chip_volt();
+
+/**
+ * @brief get SPI RAM size
+ * @return
+ *     - ESP_SPIRAM_SIZE_INVALID if SPI RAM not enabled or not valid
+ *     - SPI RAM size
+ */
+esp_spiram_size_t esp_spiram_get_chip_size();
+
 /**
  * @brief Initialize spiram interface/hardware. Normally called from cpu_start.c.
  *
index 5cdd6d9d6e4dadd7527828e4694354e976faf213..f486b7aaf6ffb4ff7982b54422535de32c50fef2 100644 (file)
@@ -127,6 +127,26 @@ esp_err_t esp_wifi_internal_reg_rxcb(wifi_interface_t ifx, wifi_rxcb_t fn);
   */
 esp_err_t esp_wifi_internal_set_sta_ip(void);
 
+/**
+  * @brief  enable or disable transmitting WiFi MAC frame with fixed rate
+  *
+  * @attention 1. If fixed rate is enabled, both management and data frame are transmitted with fixed rate
+  * @attention 2. Make sure that the receiver is able to receive the frame with the fixed rate if you want the frame to be received
+  *
+  * @param  ifx : wifi interface
+  * @param  en : false - disable, true - enable
+  * @param  rate : PHY rate
+  *
+  * @return
+  *    - ERR_OK  : succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
+  *    - ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start
+  *    - ESP_ERR_WIFI_IF : invalid WiFi interface
+  *    - ESP_ERR_INVALID_ARG : invalid rate
+  *    - ESP_ERR_NOT_SUPPORTED : do not support to set fixed rate if TX AMPDU is enabled
+  */
+esp_err_t esp_wifi_internal_set_fix_rate(wifi_interface_t ifx, bool en, wifi_phy_rate_t rate);
+
 /**
   * @brief     Check the MD5 values of the OS adapter header files in IDF and WiFi library
   *
index 2588d5d6ad87b082072eb9a4c09325d79efd76c9..8d331155d383c8410259958ff56c0c361240616d 100644 (file)
@@ -186,6 +186,8 @@ typedef struct {
     wifi_auth_mode_t    authmode;         /**< The weakest authmode to accept in the fast scan mode */
 }wifi_fast_scan_threshold_t;
 
+typedef wifi_fast_scan_threshold_t wifi_scan_threshold_t;    /**< wifi_fast_scan_threshold_t only used in fast scan mode once, now it enabled in all channel scan, the wifi_fast_scan_threshold_t will be remove in version 4.0 */
+
 typedef enum {
     WIFI_PS_NONE,        /**< No power save */
     WIFI_PS_MIN_MODEM,   /**< Minimum modem power saving. In this mode, station wakes up to receive beacon every DTIM period */
@@ -226,7 +228,7 @@ typedef struct {
     uint8_t channel;       /**< channel of target AP. Set to 1~13 to scan starting from the specified channel before connecting to AP. If the channel of AP is unknown, set it to 0.*/
     uint16_t listen_interval;   /**< Listen interval for ESP32 station to receive beacon when WIFI_PS_MAX_MODEM is set. Units: AP beacon intervals. Defaults to 3 if set to 0. */
     wifi_sort_method_t sort_method;    /**< sort the connect AP in the list by rssi or security mode */
-    wifi_fast_scan_threshold_t  threshold;     /**< When scan_method is set to WIFI_FAST_SCAN, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */
+    wifi_scan_threshold_t  threshold;     /**< When scan_method is set, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */
 } wifi_sta_config_t;
 
 /** @brief Configuration data for ESP32 AP or STA.
@@ -310,7 +312,7 @@ typedef struct {
     unsigned sig_mode:2;          /**< 0: non HT(11bg) packet; 1: HT(11n) packet; 3: VHT(11ac) packet */
     unsigned :16;                 /**< reserve */
     unsigned mcs:7;               /**< Modulation Coding Scheme. If is HT(11n) packet, shows the modulation, range from 0 to 76(MSC0 ~ MCS76) */
-    unsigned cwb:1;               /**< if is HT(11n) packet, shows if is HT40 packet or HT20 packet. 1: HT40 packet; 0: HT20 packet */
+    unsigned cwb:1;               /**< Channel Bandwidth of the packet. 0: 20MHz; 1: 40MHz */
     unsigned :16;                 /**< reserve */
     unsigned smoothing:1;         /**< reserve */
     unsigned not_sounding:1;      /**< reserve */
@@ -446,6 +448,47 @@ typedef struct {
                     enabled_ant1: 4;      /**< Index (in antenna GPIO configuration) of enabled WIFI_ANT_MODE_ANT1 */
 } wifi_ant_config_t;
 
+/**
+  * @brief WiFi PHY rate encodings
+  *
+  */
+typedef enum {
+    WIFI_PHY_RATE_1M_L      = 0x00, /**< 1 Mbps with long preamble */
+    WIFI_PHY_RATE_2M_L      = 0x01, /**< 2 Mbps with long preamble */
+    WIFI_PHY_RATE_5M_L      = 0x02, /**< 5.5 Mbps with long preamble */
+    WIFI_PHY_RATE_11M_L     = 0x03, /**< 11 Mbps with long preamble */
+    WIFI_PHY_RATE_2M_S      = 0x05, /**< 2 Mbps with short preamble */
+    WIFI_PHY_RATE_5M_S      = 0x06, /**< 5.5 Mbps with short preamble */
+    WIFI_PHY_RATE_11M_S     = 0x07, /**< 11 Mbps with short preamble */
+    WIFI_PHY_RATE_48M       = 0x08, /**< 48 Mbps */
+    WIFI_PHY_RATE_24M       = 0x09, /**< 24 Mbps */
+    WIFI_PHY_RATE_12M       = 0x0A, /**< 12 Mbps */
+    WIFI_PHY_RATE_6M        = 0x0B, /**< 6 Mbps */
+    WIFI_PHY_RATE_54M       = 0x0C, /**< 54 Mbps */
+    WIFI_PHY_RATE_36M       = 0x0D, /**< 36 Mbps */
+    WIFI_PHY_RATE_18M       = 0x0E, /**< 18 Mbps */
+    WIFI_PHY_RATE_9M        = 0x0F, /**< 9 Mbps */
+    WIFI_PHY_RATE_MCS0_LGI  = 0x10, /**< MCS0 with long GI, 6.5 Mbps for 20MHz, 13.5 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS1_LGI  = 0x11, /**< MCS1 with long GI, 13 Mbps for 20MHz, 27 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS2_LGI  = 0x12, /**< MCS2 with long GI, 19.5 Mbps for 20MHz, 40.5 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS3_LGI  = 0x13, /**< MCS3 with long GI, 26 Mbps for 20MHz, 54 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS4_LGI  = 0x14, /**< MCS4 with long GI, 39 Mbps for 20MHz, 81 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS5_LGI  = 0x15, /**< MCS5 with long GI, 52 Mbps for 20MHz, 108 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS6_LGI  = 0x16, /**< MCS6 with long GI, 58.5 Mbps for 20MHz, 121.5 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS7_LGI  = 0x17, /**< MCS7 with long GI, 65 Mbps for 20MHz, 135 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS0_SGI  = 0x18, /**< MCS0 with short GI, 7.2 Mbps for 20MHz, 15 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS1_SGI  = 0x19, /**< MCS1 with short GI, 14.4 Mbps for 20MHz, 30 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS2_SGI  = 0x1A, /**< MCS2 with short GI, 21.7 Mbps for 20MHz, 45 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS3_SGI  = 0x1B, /**< MCS3 with short GI, 28.9 Mbps for 20MHz, 60 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS4_SGI  = 0x1C, /**< MCS4 with short GI, 43.3 Mbps for 20MHz, 90 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS5_SGI  = 0x1D, /**< MCS5 with short GI, 57.8 Mbps for 20MHz, 120 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS6_SGI  = 0x1E, /**< MCS6 with short GI, 65 Mbps for 20MHz, 135 Mbps for 40MHz */
+    WIFI_PHY_RATE_MCS7_SGI  = 0x1F, /**< MCS7 with short GI, 72.2 Mbps for 20MHz, 150 Mbps for 40MHz */
+    WIFI_PHY_RATE_LORA_250K = 0x29, /**< 250 Kbps */
+    WIFI_PHY_RATE_LORA_500K = 0x2A, /**< 500 Kbps */
+    WIFI_PHY_RATE_MAX,
+} wifi_phy_rate_t;
+
 #ifdef __cplusplus
 }
 #endif
index 0c1876e585634dc537635c88ddd3bd8da96ae520..90c0b446886d3deb638e220d57c2d2490169663e 100644 (file)
@@ -51,7 +51,7 @@ struct syscall_stub_table
     int (*_rename_r)(struct _reent *r, const char*, const char*);
     clock_t (*_times_r)(struct _reent *r, struct tms *);
     int (*_gettimeofday_r) (struct _reent *r, struct timeval *, void *);
-    void (*_raise_r)(struct _reent *r);
+    void (*_raise_r)(struct _reent *r); /* function signature is incorrect in ROM */
     int (*_unlink_r)(struct _reent *r, const char*);
     int (*_link_r)(struct _reent *r, const char*, const char*);
     int (*_stat_r)(struct _reent *r, const char*, struct stat *);
index 1f3947baac2e6c9b28ff3d234ce528fde22a31ad..21470e6f403200bf0d0171e36348b50cdfcc9549 100644 (file)
@@ -52,6 +52,7 @@ SECTIONS
   /* Send .iram0 code to iram */
   .iram0.vectors :
   {
+    _iram_start = ABSOLUTE(.);
     /* Vectors go to IRAM */
     _init_start = ABSOLUTE(.);
     /* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */
@@ -85,11 +86,7 @@ SECTIONS
     *(.init.literal)
     *(.init)
     _init_end = ABSOLUTE(.);
-
-    /* This goes here, not at top of linker script, so addr2line finds it last,
-       and uses it in preference to the first symbol in IRAM */
-    _iram_start = ABSOLUTE(0);
-  } > iram0_0_seg
+} > iram0_0_seg
 
   .iram0.text :
   {
@@ -104,15 +101,17 @@ SECTIONS
     *libapp_trace.a:(.literal .text .literal.* .text.*)
     *libxtensa-debug-module.a:eri.o(.literal .text .literal.* .text.*)
     *librtc.a:(.literal .text .literal.* .text.*)
-    *libsoc.a:(.literal .text .literal.* .text.*)
+    *libsoc.a:rtc_*.o(.literal .text .literal.* .text.*)
+    *libsoc.a:cpu_util.o(.literal .text .literal.* .text.*)
     *libhal.a:(.literal .text .literal.* .text.*)
     *libgcc.a:lib2funcs.o(.literal .text .literal.* .text.*)
     *libspi_flash.a:spi_flash_rom_patch.o(.literal .text .literal.* .text.*)
     *libgcov.a:(.literal .text .literal.* .text.*)
     INCLUDE esp32.spiram.rom-functions-iram.ld
     _iram_text_end = ABSOLUTE(.);
+    _iram_end = ABSOLUTE(.);
   } > iram0_0_seg
-  
+
   .dram0.data :
   {
     _data_start = ABSOLUTE(.);
@@ -231,6 +230,11 @@ SECTIONS
     *(.xt_except_desc_end)
     *(.dynamic)
     *(.gnu.version_d)
+    /* Addresses of memory regions reserved via
+       SOC_RESERVE_MEMORY_REGION() */
+    soc_reserved_memory_region_start = ABSOLUTE(.);
+    KEEP (*(.reserved_memory_address))
+    soc_reserved_memory_region_end = ABSOLUTE(.);
     _rodata_end = ABSOLUTE(.);
     /* Literals are also RO data. */
     _lit4_start = ABSOLUTE(.);
index 147e6c20e13237efadd9b73280374d2e3987acdd..3a57e719887cfa3f72abc27e7d3102800cd7eb65 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 147e6c20e13237efadd9b73280374d2e3987acdd
+Subproject commit 3a57e719887cfa3f72abc27e7d3102800cd7eb65
index 8edb70b23329c9384d33d9ea87b6ddb4adf8fca1..5a000574be081b3044b44eba7fcb06928fd87ec1 100644 (file)
@@ -30,6 +30,7 @@
 #include "soc/timer_group_reg.h"
 #include "soc/cpu.h"
 #include "soc/rtc.h"
+#include "soc/rtc_wdt.h"
 
 #include "esp_gdbstub.h"
 #include "esp_panic.h"
@@ -374,32 +375,6 @@ static inline void disableAllWdts()
     TIMERG1.wdt_wprotect = 0;
 }
 
-static void esp_panic_wdt_start()
-{
-    if (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN)) {
-        return;
-    }
-    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
-    WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
-    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
-    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, 7);
-    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_SYSTEM);
-    // 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
-    // @ 115200 UART speed it will take more than 6 sec to print them out.
-    WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * 7);
-    REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
-    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
-}
-
-void esp_panic_wdt_stop()
-{
-    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
-    WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
-    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_OFF);
-    REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
-    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
-}
-
 static void esp_panic_dig_reset() __attribute__((noreturn));
 
 static void esp_panic_dig_reset()
@@ -528,7 +503,18 @@ static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
 
     int core_id = xPortGetCoreID();
     // start panic WDT to restart system if we hang in this handler
-    esp_panic_wdt_start();
+    if (!rtc_wdt_is_on()) {
+        rtc_wdt_protect_off();
+        rtc_wdt_disable();
+        rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us);
+        rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us);
+        rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_SYSTEM);
+        // 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
+        // @ 115200 UART speed it will take more than 6 sec to print them out.
+        rtc_wdt_set_time(RTC_WDT_STAGE0, 7000);
+        rtc_wdt_enable();
+        rtc_wdt_protect_on();
+    }
 
     //Feed the watchdogs, so they will give us time to print out debug info
     reconfigureAllWdts();
@@ -553,7 +539,7 @@ static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
 
 #if CONFIG_ESP32_PANIC_GDBSTUB
     disableAllWdts();
-    esp_panic_wdt_stop();
+    rtc_wdt_disable();
     panicPutStr("Entering gdb stub now.\r\n");
     esp_gdbstub_panic_handler(frame);
 #else
@@ -574,7 +560,7 @@ static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
         reconfigureAllWdts();
     }
 #endif /* CONFIG_ESP32_ENABLE_COREDUMP */
-    esp_panic_wdt_stop();
+    rtc_wdt_disable();
 #if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
     panicPutStr("Rebooting...\r\n");
     if (frame->exccause != PANIC_RSN_CACHEERR) {
index f4cefb98b621ecb619d3e81aa549d715c7d5a34c..91713ad6bb1640e7da4b1e4756a49c454d28736f 100644 (file)
@@ -32,6 +32,7 @@
 #include "soc/spi_reg.h"
 #include "soc/sens_reg.h"
 #include "soc/dport_reg.h"
+#include "soc/rtc_wdt.h"
 #include "driver/rtc_io.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
@@ -238,27 +239,6 @@ void IRAM_ATTR esp_deep_sleep_start()
     }
 }
 
-static void rtc_wdt_enable(int time_ms)
-{
-    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
-    WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
-    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
-    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, 7);
-    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_RTC);
-    WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * time_ms / 1000);
-    SET_PERI_REG_MASK(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN | RTC_CNTL_WDT_PAUSE_IN_SLP);
-    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
-}
-
-static void rtc_wdt_disable()
-{
-    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
-    WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
-    REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_OFF);
-    REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
-    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
-}
-
 /**
  * Helper function which handles entry to and exit from light sleep
  * Placed into IRAM as flash may need some time to be powered on.
@@ -326,7 +306,17 @@ esp_err_t esp_light_sleep_start()
     rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config();
 
     // Safety net: enable WDT in case exit from light sleep fails
-    rtc_wdt_enable(1000);
+    bool wdt_was_enabled = rtc_wdt_is_on(); // If WDT was enabled in the user code, then do not change it here.
+    if (!wdt_was_enabled) {
+        rtc_wdt_protect_off();
+        rtc_wdt_disable();
+        rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us);
+        rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us);
+        rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC);
+        rtc_wdt_set_time(RTC_WDT_STAGE0, 1000);
+        rtc_wdt_enable();
+        rtc_wdt_protect_on();
+    }
 
     // Enter sleep, then wait for flash to be ready on wakeup
     esp_err_t err = esp_light_sleep_inner(pd_flags,
@@ -352,7 +342,9 @@ esp_err_t esp_light_sleep_start()
 
     esp_timer_impl_unlock();
     DPORT_STALL_OTHER_CPU_END();
-    rtc_wdt_disable();
+    if (!wdt_was_enabled) {
+        rtc_wdt_disable();
+    }
     portEXIT_CRITICAL(&light_sleep_lock);
     return err;
 }
index 8ae7c0ec0b28f381c45f93af70089e55979c1e85..72198734e160239b9e666443c039503ceaeb0a6a 100644 (file)
@@ -24,6 +24,7 @@ we add more types of external RAM memory, this can be made into a more intellige
 #include "sdkconfig.h"
 #include "esp_attr.h"
 #include "esp_err.h"
+#include "esp_spiram.h"
 #include "spiram_psram.h"
 #include "esp_log.h"
 #include "freertos/FreeRTOS.h"
@@ -103,6 +104,39 @@ void IRAM_ATTR esp_spiram_init_cache()
 #endif
 }
 
+esp_spiram_volt_t esp_spiram_get_chip_volt()
+{
+    if (!spiram_inited) {
+        ESP_LOGE(TAG, "SPI RAM not initialized");
+        return ESP_SPIRAM_VOLT_INVALID;
+    }
+    psram_volt_t volt = psram_get_volt();
+    switch (volt) {
+        case PSRAM_VOLT_1V8:
+            return ESP_SPIRAM_VOLT_1V8;
+        case PSRAM_VOLT_3V3:
+            return ESP_SPIRAM_VOLT_3V3;
+        default:
+            return ESP_SPIRAM_VOLT_INVALID;
+    }
+}
+
+esp_spiram_size_t esp_spiram_get_chip_size()
+{
+    if (!spiram_inited) {
+        ESP_LOGE(TAG, "SPI RAM not initialized");
+        return ESP_SPIRAM_SIZE_INVALID;
+    }
+    psram_size_t psram_size = psram_get_size();
+    switch (psram_size) {
+        case PSRAM_SIZE_32MBITS:
+            return ESP_SPIRAM_SIZE_32MBITS;
+        case PSRAM_SIZE_64MBITS:
+            return ESP_SPIRAM_SIZE_64MBITS;
+        default:
+            return ESP_SPIRAM_SIZE_INVALID;
+    }
+}
 
 esp_err_t esp_spiram_init()
 {
index ed20375da8ed4337ae773cb42ffe36b9e8842d02..2aa3b422bb172fb56f87bc77cb0ce564697f7dc9 100644 (file)
 #include "soc/rtc.h"
 
 //Commands for PSRAM chip
-#define PSRAM_READ              0x03
-#define PSRAM_FAST_READ         0x0B
-#define PSRAM_FAST_READ_DUMMY   0x3
-#define PSRAM_FAST_READ_QUAD    0xEB
-#define PSRAM_WRITE             0x02
-#define PSRAM_QUAD_WRITE        0x38
-#define PSRAM_ENTER_QMODE       0x35
-#define PSRAM_EXIT_QMODE        0xF5
-#define PSRAM_RESET_EN          0x66
-#define PSRAM_RESET             0x99
-#define PSRAM_SET_BURST_LEN     0xC0
-#define PSRAM_DEVICE_ID         0x9F
-
-#if CONFIG_SPIRAM_TYPE_ESPPSRAM32
-
-#define PSRAM_MFG_ID_M          0xff
-#define PSRAM_MFG_ID_S             8
-#define PSRAM_MFG_ID_V          0x5d
-
-#endif
+#define PSRAM_READ                 0x03
+#define PSRAM_FAST_READ            0x0B
+#define PSRAM_FAST_READ_DUMMY      0x3
+#define PSRAM_FAST_READ_QUAD       0xEB
+#define PSRAM_FAST_READ_QUAD_DUMMY 0x5
+#define PSRAM_WRITE                0x02
+#define PSRAM_QUAD_WRITE           0x38
+#define PSRAM_ENTER_QMODE          0x35
+#define PSRAM_EXIT_QMODE           0xF5
+#define PSRAM_RESET_EN             0x66
+#define PSRAM_RESET                0x99
+#define PSRAM_SET_BURST_LEN        0xC0
+#define PSRAM_DEVICE_ID            0x9F
+
+typedef enum {
+    PSRAM_EID_32MBIT_1V8 = 0x20,    /*!< psram EID for 32MBit 1.8V */
+    PSRAM_EID_64MBIT_1V8 = 0x26,    /*!< psram EID for 64MBit 1.8V */
+    PSRAM_EID_64MBIT_3V3 = 0x46,    /*!< psram EID for 64MBit 3.3V */
+} psram_type_t;
+
+typedef enum {
+    PSRAM_CLK_MODE_NORM = 0,    /*!< Normal SPI mode */
+    PSRAM_CLK_MODE_DCLK = 1,    /*!< Two extra clock cycles after CS is set high level */
+} psram_clk_mode_t;
+
+#define PSRAM_ID_KGD_M          0xff
+#define PSRAM_ID_KGD_S             8
+#define PSRAM_ID_KGD            0x5d
+#define PSRAM_ID_EID_M          0xff
+#define PSRAM_ID_EID_S            16
+
+#define PSRAM_KGD(id)          (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M)
+#define PSRAM_EID(id)          (((id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M)
+#define PSRAM_IS_VALID(id)     (PSRAM_KGD(id) == PSRAM_ID_KGD)
+#define PSRAM_IS_1V8(id)       ((PSRAM_EID(id) == PSRAM_EID_32MBIT_1V8) || (PSRAM_EID(id) == PSRAM_EID_64MBIT_1V8))
+#define PSRAM_IS_3V3(id)       (PSRAM_EID(id) == PSRAM_EID_64MBIT_3V3)
+#define PSRAM_IS_64MBIT(id)    ((PSRAM_EID(id) == PSRAM_EID_64MBIT_3V3) || (PSRAM_EID(id) == PSRAM_EID_64MBIT_1V8))
+#define PSRAM_IS_32MBIT(id)    (PSRAM_EID(id) == PSRAM_EID_32MBIT_1V8)
 
 // IO-pins for PSRAM. These need to be in the VDD_SIO power domain because all chips we
 // currently support are 1.8V parts.
@@ -94,6 +112,8 @@ typedef enum {
 } psram_spi_num_t;
 
 static psram_cache_mode_t s_psram_mode = PSRAM_CACHE_MAX;
+static psram_clk_mode_t s_clk_mode = PSRAM_CLK_MODE_DCLK;
+static uint32_t s_psram_id = 0;
 
 /* dummy_len_plus values defined in ROM for SPI flash configuration */
 extern uint8_t g_rom_spiflash_dummy_len_plus[];
@@ -280,7 +300,7 @@ static int psram_cmd_config(psram_spi_num_t spi_num, psram_cmd_t* pInData)
     return 0;
 }
 
-void psram_cmd_end(int spi_num) {
+static void psram_cmd_end(int spi_num) {
     while (READ_PERI_REG(SPI_CMD_REG(spi_num)) & SPI_USR);
     WRITE_PERI_REG(SPI_USER_REG(spi_num), backup_usr[spi_num]);
     WRITE_PERI_REG(SPI_USER1_REG(spi_num), backup_usr1[spi_num]);
@@ -292,17 +312,19 @@ static void psram_disable_qio_mode(psram_spi_num_t spi_num)
 {
     psram_cmd_t ps_cmd;
     uint32_t cmd_exit_qpi;
-    switch (s_psram_mode) {
-        case PSRAM_CACHE_F80M_S80M:
-            cmd_exit_qpi = PSRAM_EXIT_QMODE;
-            ps_cmd.txDataBitLen = 8;
-            break;
-        case PSRAM_CACHE_F80M_S40M:
-        case PSRAM_CACHE_F40M_S40M:
-        default:
-            cmd_exit_qpi = PSRAM_EXIT_QMODE << 8;
-            ps_cmd.txDataBitLen = 16;
-            break;
+    cmd_exit_qpi = PSRAM_EXIT_QMODE;
+    ps_cmd.txDataBitLen = 8;
+    if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
+        switch (s_psram_mode) {
+            case PSRAM_CACHE_F80M_S80M:
+                break;
+            case PSRAM_CACHE_F80M_S40M:
+            case PSRAM_CACHE_F40M_S40M:
+            default:
+                cmd_exit_qpi = PSRAM_EXIT_QMODE << 8;
+                ps_cmd.txDataBitLen = 16;
+                break;
+        }
     }
     ps_cmd.txData = &cmd_exit_qpi;
     ps_cmd.cmd = 0;
@@ -322,29 +344,34 @@ static void psram_read_id(uint32_t* dev_id)
 {
     psram_spi_num_t spi_num = PSRAM_SPI_1;
     psram_disable_qio_mode(spi_num);
-    uint32_t addr = (PSRAM_DEVICE_ID << 24) | 0;
-    uint32_t dummy_bits = 0;
+    uint32_t dummy_bits = 0 + extra_dummy;
     psram_cmd_t ps_cmd;
-    switch (s_psram_mode) {
-        case PSRAM_CACHE_F80M_S80M:
-            dummy_bits = 0 + extra_dummy;
-            ps_cmd.cmdBitLen = 0;
-            break;
-        case PSRAM_CACHE_F80M_S40M:
-        case PSRAM_CACHE_F40M_S40M:
-        default:
-            dummy_bits = 0 + extra_dummy;
-            ps_cmd.cmdBitLen = 2;   //this two bits is used to delay 2 clock cycle
-            break;
+
+    uint32_t addr = 0;
+    ps_cmd.addrBitLen = 3 * 8;
+    ps_cmd.cmd = PSRAM_DEVICE_ID;
+    ps_cmd.cmdBitLen = 8;
+    if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
+        switch (s_psram_mode) {
+            case PSRAM_CACHE_F80M_S80M:
+                break;
+            case PSRAM_CACHE_F80M_S40M:
+            case PSRAM_CACHE_F40M_S40M:
+            default:
+                ps_cmd.cmdBitLen = 2;   //this two bits is used to delay 2 clock cycle
+                ps_cmd.cmd = 0;
+                addr = (PSRAM_DEVICE_ID << 24) | 0;
+                ps_cmd.addrBitLen = 4 * 8;
+                break;
+        }
     }
-    ps_cmd.cmd = 0;
     ps_cmd.addr = &addr;
-    ps_cmd.addrBitLen = 4 * 8;
     ps_cmd.txDataBitLen = 0;
     ps_cmd.txData = NULL;
     ps_cmd.rxDataBitLen = 4 * 8;
     ps_cmd.rxData = dev_id;
     ps_cmd.dummyBitLen = dummy_bits;
+
     psram_cmd_config(spi_num, &ps_cmd);
     psram_clear_spi_fifo(spi_num);
     psram_cmd_recv_start(spi_num, ps_cmd.rxData, ps_cmd.rxDataBitLen / 8, PSRAM_CMD_SPI);
@@ -356,15 +383,18 @@ static esp_err_t IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spi_num)
 {
     psram_cmd_t ps_cmd;
     uint32_t addr = (PSRAM_ENTER_QMODE << 24) | 0;
-    switch (s_psram_mode) {
-        case PSRAM_CACHE_F80M_S80M:
-            ps_cmd.cmdBitLen = 0;
-            break;
-        case PSRAM_CACHE_F80M_S40M:
-        case PSRAM_CACHE_F40M_S40M:
-        default:
-            ps_cmd.cmdBitLen = 2;
-            break;
+
+    ps_cmd.cmdBitLen = 0;
+    if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
+        switch (s_psram_mode) {
+            case PSRAM_CACHE_F80M_S80M:
+                break;
+            case PSRAM_CACHE_F80M_S40M:
+            case PSRAM_CACHE_F40M_S40M:
+            default:
+                ps_cmd.cmdBitLen = 2;
+                break;
+        }
     }
     ps_cmd.cmd = 0;
     ps_cmd.addr = &addr;
@@ -491,6 +521,28 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
     PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
 }
 
+psram_volt_t psram_get_volt()
+{
+    if (PSRAM_IS_1V8(s_psram_id)) {
+        return PSRAM_VOLT_1V8;
+    } else if (PSRAM_IS_3V3(s_psram_id)) {
+        return PSRAM_VOLT_3V3;
+    } else {
+        return PSRAM_VOLT_MAX;
+    }
+}
+
+psram_size_t psram_get_size()
+{
+    if (PSRAM_IS_32MBIT(s_psram_id)) {
+        return PSRAM_SIZE_32MBITS;
+    } else if (PSRAM_IS_64MBIT(s_psram_id)) {
+        return PSRAM_SIZE_64MBITS;
+    } else {
+        return PSRAM_SIZE_MAX;
+    }
+}
+
 //psram gpio init , different working frequency we have different solutions
 esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode)   //psram init
 {
@@ -507,17 +559,6 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
         return ESP_FAIL;
     }
 
-    /*   note: If the third mode(80Mhz+80Mhz) is enabled, VSPI port will be occupied by the system,
-         Application code should never touch VSPI hardware in this case.  We try to stop applications
-         from doing this using the drivers by claiming the port for ourselves*/
-    if (mode == PSRAM_CACHE_F80M_S80M) {
-        periph_module_enable(PERIPH_VSPI_MODULE);
-        bool r=spicommon_periph_claim(VSPI_HOST);
-        if (!r) {
-            return ESP_ERR_INVALID_STATE;
-        }
-    }
-
     WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG, BIT(PSRAM_CLK_IO) | BIT(PSRAM_CS_IO));   //DISABLE OUPUT FOR IO16/17
     assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
     s_psram_mode = mode;
@@ -532,21 +573,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
             psram_spi_init(PSRAM_SPI_1, mode);
             CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
             gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0);
-            gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
-            //use spi3 clock,but use spi1 data/cs wires
-            //We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it 
-            //is in progress, then cutting the clock (but not the reset!) to that peripheral.
-            WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
-            WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M);   //SET 80M AND CLEAR OTHERS
-            SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
-            uint32_t spi_status;
-            while (1) {
-                spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
-                if (spi_status != 0 && spi_status != 1) {
-                    DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
-                    break;
-                }
-            }
+            gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
             break;
         case PSRAM_CACHE_F80M_S40M:
         case PSRAM_CACHE_F40M_S40M:
@@ -585,27 +612,58 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
     PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CS_IO], PIN_FUNC_GPIO);
     PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], PIN_FUNC_GPIO);
 
+    psram_read_id(&s_psram_id);
+    if (!PSRAM_IS_VALID(s_psram_id)) {
+        return ESP_FAIL;
+    }
     uint32_t flash_id = g_rom_flashchip.device_id;
-    if (flash_id == FLASH_ID_GD25LQ32C) {
-        #if CONFIG_SPIRAM_TYPE_ESPPSRAM32
+    if (flash_id == FLASH_ID_GD25LQ32C && PSRAM_IS_1V8(s_psram_id)) {
         // Set drive ability for 1.8v flash in 80Mhz.
-        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S);
-        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S);
-        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S);
-        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S);
-        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S);
-        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
-        SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CS_IO], FUN_DRV, 3, FUN_DRV_S);
-        SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV, 3, FUN_DRV_S);
-        #endif
+        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U,      FUN_DRV_V, 3, FUN_DRV_S);
+        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U,      FUN_DRV_V, 3, FUN_DRV_S);
+        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U,      FUN_DRV_V, 3, FUN_DRV_S);
+        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U,      FUN_DRV_V, 3, FUN_DRV_S);
+        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U,        FUN_DRV_V, 3, FUN_DRV_S);
+        SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U,        FUN_DRV_V, 3, FUN_DRV_S);
+        SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CS_IO],  FUN_DRV_V, 3, FUN_DRV_S);
+        SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV_V, 3, FUN_DRV_S);
     }
-    uint32_t id;
-    psram_read_id(&id);
-    if (((id >> PSRAM_MFG_ID_S) & PSRAM_MFG_ID_M) != PSRAM_MFG_ID_V) {
-        return ESP_FAIL;
+    if (PSRAM_EID(s_psram_id) == PSRAM_EID_64MBIT_1V8) {
+        // For this psram, we don't need any extra clock cycles after cs get back to high level
+        s_clk_mode = PSRAM_CLK_MODE_NORM;
+        gpio_matrix_out(PSRAM_INTERNAL_IO_28, SIG_GPIO_OUT_IDX, 0, 0);
+        gpio_matrix_out(PSRAM_INTERNAL_IO_29, SIG_GPIO_OUT_IDX, 0, 0);
+        gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
+    } else if (PSRAM_EID(s_psram_id) == PSRAM_EID_32MBIT_1V8 || PSRAM_EID(s_psram_id) == PSRAM_EID_64MBIT_3V3) {
+        s_clk_mode = PSRAM_CLK_MODE_DCLK;
+        if (mode == PSRAM_CACHE_F80M_S80M) {
+            /*   note: If the third mode(80Mhz+80Mhz) is enabled for 32MBit 1V8 psram and 64MBit 3.3v psram,
+                 VSPI port will be occupied by the system.
+                 Application code should never touch VSPI hardware in this case.  We try to stop applications
+                 from doing this using the drivers by claiming the port for ourselves*/
+            periph_module_enable(PERIPH_VSPI_MODULE);
+            bool r=spicommon_periph_claim(VSPI_HOST);
+            if (!r) {
+                return ESP_ERR_INVALID_STATE;
+            }
+            gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
+            //use spi3 clock,but use spi1 data/cs wires
+            //We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it
+            //is in progress, then cutting the clock (but not the reset!) to that peripheral.
+            WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
+            WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M);   //SET 80M AND CLEAR OTHERS
+            SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
+            uint32_t spi_status;
+            while (1) {
+                spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
+                if (spi_status != 0 && spi_status != 1) {
+                    DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
+                    break;
+                }
+            }
+        }
     }
     psram_enable_qio_mode(PSRAM_SPI_1);
-
     psram_cache_init(mode, vaddrmode);
     return ESP_OK;
 }
@@ -624,27 +682,15 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
             CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31));   //flash 1 div clk,80+40;
             CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0. FLASH DIV 2+SRAM DIV4
             WRITE_PERI_REG(SPI_CLOCK_REG(0), SPI_CLK_EQU_SYSCLK_M);   //SET 1DIV CLOCK AND RESET OTHER PARAMS
-            SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M);   //enable cache read dummy
-            SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
-                    SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache :  40m--+1dummy,80m--+2dummy
-            SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
             break;
         case PSRAM_CACHE_F80M_S40M:
             SET_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
             CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0.
-            SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
-            SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
-                    SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache :  40m--+1dummy,80m--+2dummy
-            SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
             break;
         case PSRAM_CACHE_F40M_S40M:
         default:
             CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
             CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div
-            SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
-            SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
-                    SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache :  40m--+1dummy,80m--+2dummy
-            SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
             break;
     }
     SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_WCMD_M);     // cache write command enable
@@ -652,30 +698,38 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
     SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_QIO_M);     //enable qio mode for cache command
     CLEAR_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_DIO_M);     //disable dio mode for cache command
 
+    SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M);   //enable cache read dummy
+    SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
+    SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
+            SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
+    SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, PSRAM_QUAD_WRITE,
+            SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
+    SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
+            SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
+    SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ_QUAD,
+            SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
+    SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
+            SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache :  40m--+1dummy,80m--+2dummy
 
     //config sram cache r/w command
     switch (psram_cache_mode) {
         case PSRAM_CACHE_F80M_S80M: //in this mode , no delay is needed
-            SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
-                    SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
-            SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, PSRAM_QUAD_WRITE,
-                    SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
-            SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
-                    SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
-            SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ,
-                    SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
             break;
         case PSRAM_CACHE_F80M_S40M: //is sram is @40M, need 2 cycles of delay
         case PSRAM_CACHE_F40M_S40M:
         default:
-            SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15,
-                    SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache
-            SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ) << 8),
-                    SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd)
-            SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15,
-                    SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache)
-            SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, ((PSRAM_QUAD_WRITE) << 8),
-                    SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay)
+            if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
+                SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15,
+                        SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache
+                SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ_QUAD) << 8),
+                        SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd)
+                SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15,
+                        SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache)
+                SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, ((PSRAM_QUAD_WRITE) << 8),
+                        SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay)
+                SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
+                        SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache :  40m--+1dummy,80m--+2dummy
+            }
             break;
     }
 
@@ -698,6 +752,11 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
 
     CLEAR_PERI_REG_MASK(SPI_PIN_REG(0), SPI_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
 
+    if (s_clk_mode == PSRAM_CLK_MODE_NORM) {    //different
+        SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD);
+        // Set cs time.
+        SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 1, SPI_SETUP_TIME_S);
+    }
 }
 
 #endif // CONFIG_SPIRAM_SUPPORT
index 10de4e1d6c02e20abe7d356837e2176d94d874f5..1756eed73ddef67b74d6bb6a7534325af14a884d 100644 (file)
@@ -26,6 +26,17 @@ typedef enum {
     PSRAM_CACHE_MAX,
 } psram_cache_mode_t;
 
+typedef enum {
+    PSRAM_VOLT_3V3 = 0,
+    PSRAM_VOLT_1V8 = 1,
+    PSRAM_VOLT_MAX,
+} psram_volt_t;
+
+typedef enum {
+    PSRAM_SIZE_32MBITS = 0,
+    PSRAM_SIZE_64MBITS = 1,
+    PSRAM_SIZE_MAX,
+} psram_size_t;
 
 /*
 See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the definitions of these modes.
@@ -34,12 +45,29 @@ Important is that NORMAL works with the app CPU cache disabled, but gives huge c
 issues when both app and pro CPU are enabled. LOWHIGH and EVENODD do not have these coherency
 issues but cannot be used when the app CPU cache is disabled.
 */
+
 typedef enum {
     PSRAM_VADDR_MODE_NORMAL=0, ///< App and pro CPU use their own flash cache for external RAM access
     PSRAM_VADDR_MODE_LOWHIGH,  ///< App and pro CPU share external RAM caches: pro CPU has low 2M, app CPU has high 2M
     PSRAM_VADDR_MODE_EVENODD,  ///< App and pro CPU share external RAM caches: pro CPU does even 32yte ranges, app does odd ones.
 } psram_vaddr_mode_t;
 
+/**
+ * @brief get psram voltage
+ * @return
+ *     - PSRAM_VOLT_MAX if psram not enabled or not valid.
+ *     - PSRAM voltage
+ */
+psram_volt_t psram_get_volt();
+
+/**
+ * @brief get psram size
+ * @return
+ *     - PSRAM_SIZE_MAX if psram not enabled or not valid
+ *     - PSRAM size
+ */
+psram_size_t psram_get_size();
+
 /**
  * @brief psram cache enable function
  *
index 8068f3bc4f61e4b134ff625b081bd9b5627f8a53..f56bf622e2c0b5eae2c9852336f7044a5b0c66a0 100644 (file)
@@ -31,6 +31,7 @@
 #include "soc/timer_group_struct.h"
 #include "soc/cpu.h"
 #include "soc/rtc.h"
+#include "soc/rtc_wdt.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 #include "freertos/xtensa_api.h"
@@ -270,14 +271,15 @@ void IRAM_ATTR esp_restart_noos()
     xt_ints_off(0xFFFFFFFF);
 
     // Enable RTC watchdog for 1 second
-    REG_WRITE(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
-    REG_WRITE(RTC_CNTL_WDTCONFIG0_REG,
-            RTC_CNTL_WDT_FLASHBOOT_MOD_EN_M |
-            (RTC_WDT_STG_SEL_RESET_SYSTEM << RTC_CNTL_WDT_STG0_S) |
-            (RTC_WDT_STG_SEL_RESET_RTC << RTC_CNTL_WDT_STG1_S) |
-            (1 << RTC_CNTL_WDT_SYS_RESET_LENGTH_S) |
-            (1 << RTC_CNTL_WDT_CPU_RESET_LENGTH_S) );
-    REG_WRITE(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * 1);
+    rtc_wdt_protect_off();
+    rtc_wdt_disable();
+    rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC);
+    rtc_wdt_set_stage(RTC_WDT_STAGE1, RTC_WDT_STAGE_ACTION_RESET_SYSTEM);
+    rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_200ns);
+    rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_200ns);
+    rtc_wdt_set_time(RTC_WDT_STAGE0, 1000);
+    rtc_wdt_enable();
+    rtc_wdt_protect_on();
 
     // Reset and stall the other CPU.
     // CPU must be reset before stalling, in case it was running a s32c1i
index 0681660ff1ea30e0bc0dcfe673b513f0b3479bb4..cdca805df40692fda22c73466167ecd6df591744 100644 (file)
@@ -83,8 +83,8 @@ TEST_CASE("wifi stop and deinit","[wifi]")
     //init nvs
     ESP_LOGI(TAG, EMPH_STR("nvs_flash_init"));
     esp_err_t r = nvs_flash_init();
-    if (r == ESP_ERR_NVS_NO_FREE_PAGES) {
-        ESP_LOGI(TAG, EMPH_STR("no free pages, erase.."));
+    if (r == ESP_ERR_NVS_NO_FREE_PAGES || r == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        ESP_LOGI(TAG, EMPH_STR("no free pages or nvs version mismatch, erase.."));
         TEST_ESP_OK(nvs_flash_erase());
         r = nvs_flash_init();
     } 
index f504ba1d211114aebf84a4d69c910929ff67b2e7..e21b93da2f6228d7d01a150a56eff718946dfe31 100644 (file)
 
 static const char *TAG = "HTTP_CLIENT";
 
+/**
+ * HTTP Buffer
+ */
 typedef struct {
-    char *data;
-    int len;
-    char *raw_data;
-    int raw_len;
+    char *data;         /*!< The HTTP data received from the server */
+    int len;            /*!< The HTTP data len received from the server */
+    char *raw_data;     /*!< The HTTP data after decoding */
+    int raw_len;        /*!< The HTTP data len after decoding */
+    char *output_ptr;   /*!< The destination address of the data to be copied to after decoding */
 } esp_http_buffer_t;
+
 /**
  * private HTTP Data structure
  */
@@ -130,7 +135,8 @@ static const char *HTTP_METHOD_MAPPING[] = {
     "POST",
     "PUT",
     "PATCH",
-    "DELETE"
+    "DELETE",
+    "HEAD"
 };
 
 /**
@@ -232,9 +238,14 @@ static int http_on_body(http_parser *parser, const char *at, size_t length)
 {
     esp_http_client_t *client = parser->data;
     ESP_LOGD(TAG, "http_on_body %d", length);
-    client->response->buffer->raw_data = (char*)at;
-    client->response->buffer->raw_len = length;
+    client->response->buffer->raw_data = (char *)at;
+    if (client->response->buffer->output_ptr) {
+        memcpy(client->response->buffer->output_ptr, (char *)at, length);
+        client->response->buffer->output_ptr += length;
+    }
+
     client->response->data_process += length;
+    client->response->buffer->raw_len += length;
     http_dispatch_event(client, HTTP_EVENT_ON_DATA, (void *)at, length);
     return 0;
 }
@@ -268,7 +279,7 @@ esp_err_t esp_http_client_delete_header(esp_http_client_handle_t client, const c
     return http_header_delete(client->request->headers, key);
 }
 
-static esp_err_t _set_config(esp_http_client_handle_t client, esp_http_client_config_t *config)
+static esp_err_t _set_config(esp_http_client_handle_t client, const esp_http_client_config_t *config)
 {
     client->connection_info.method = config->method;
     client->connection_info.port = config->port;
@@ -406,7 +417,7 @@ static esp_err_t esp_http_client_prepare(esp_http_client_handle_t client)
     return ESP_OK;
 }
 
-esp_http_client_handle_t esp_http_client_init(esp_http_client_config_t *config)
+esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *config)
 {
 
     esp_http_client_handle_t client;
@@ -552,10 +563,10 @@ static esp_err_t esp_http_check_response(esp_http_client_handle_t client)
             break;
         case HttpStatus_Unauthorized:
             auth_header = client->auth_header;
-            http_utils_trim_whitespace(&auth_header);
-            ESP_LOGI(TAG, "UNAUTHORIZED: %s", auth_header);
-            client->redirect_counter ++;
             if (auth_header) {
+                http_utils_trim_whitespace(&auth_header);
+                ESP_LOGD(TAG, "UNAUTHORIZED: %s", auth_header);
+                client->redirect_counter ++;
                 if (http_utils_str_starts_with(auth_header, "Digest") == 0) {
                     ESP_LOGD(TAG, "type = Digest");
                     client->connection_info.auth_type = HTTP_AUTH_TYPE_DIGEST;
@@ -564,7 +575,7 @@ static esp_err_t esp_http_check_response(esp_http_client_handle_t client)
                     client->connection_info.auth_type = HTTP_AUTH_TYPE_BASIC;
                 } else {
                     client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE;
-                    ESP_LOGE(TAG, "Unsupport Auth Type");
+                    ESP_LOGE(TAG, "This authentication method is not supported: %s", auth_header);
                     break;
                 }
 
@@ -579,6 +590,9 @@ static esp_err_t esp_http_check_response(esp_http_client_handle_t client)
                 client->auth_data->nonce = http_utils_get_string_between(auth_header, "nonce=\"", "\"");
                 client->auth_data->opaque = http_utils_get_string_between(auth_header, "opaque=\"", "\"");
                 client->process_again = 1;
+            } else {
+                client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE;
+                ESP_LOGW(TAG, "This request requires authentication, but does not provide header information for that");
             }
     }
     return ESP_OK;
@@ -695,6 +709,11 @@ static int esp_http_client_get_data(esp_http_client_handle_t client)
     if (client->state < HTTP_STATE_RES_COMPLETE_HEADER) {
         return ESP_FAIL;
     }
+
+    if (client->connection_info.method == HTTP_METHOD_HEAD) {
+        return 0;
+    }
+
     esp_http_buffer_t *res_buffer = client->response->buffer;
 
     ESP_LOGD(TAG, "data_process=%d, content_length=%d", client->response->data_process, client->response->content_length);
@@ -743,14 +762,13 @@ int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len)
         if (rlen <= 0) {
             return ridx;
         }
+        res_buffer->output_ptr = buffer + ridx;
         http_parser_execute(client->parser, client->parser_settings, res_buffer->data, rlen);
+        ridx += res_buffer->raw_len;
+        need_read -= res_buffer->raw_len;
 
-        if (res_buffer->raw_len) {
-            memcpy(buffer + ridx, res_buffer->raw_data, res_buffer->raw_len);
-            ridx += res_buffer->raw_len;
-            need_read -= res_buffer->raw_len;
-        }
         res_buffer->raw_len = 0; //clear
+        res_buffer->output_ptr = NULL;
     }
 
     return ridx;
@@ -1002,3 +1020,14 @@ bool esp_http_client_is_chunked_response(esp_http_client_handle_t client)
 {
     return client->response->is_chunked;
 }
+
+esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_handle_t client)
+{
+    if (!strcmp(client->connection_info.scheme, "https") ) {
+        return HTTP_TRANSPORT_OVER_SSL;
+    } else if (!strcmp(client->connection_info.scheme, "http")) {
+        return HTTP_TRANSPORT_OVER_TCP;
+    } else {
+        return HTTP_TRANSPORT_UNKNOWN;
+    }
+}
index b47f9263ad178a6aca3f0b4ad367d44ca728717d..159931c2c8fb6dce1ad04c8fb1a35f47b10c785b 100644 (file)
@@ -76,6 +76,7 @@ typedef enum {
     HTTP_METHOD_PUT,        /*!< HTTP PUT Method */
     HTTP_METHOD_PATCH,      /*!< HTTP PATCH Method */
     HTTP_METHOD_DELETE,     /*!< HTTP DELETE Method */
+    HTTP_METHOD_HEAD,       /*!< HTTP HEAD Method */
     HTTP_METHOD_MAX,
 } esp_http_client_method_t;
 
@@ -131,7 +132,7 @@ typedef struct {
  *     - `esp_http_client_handle_t`
  *     - NULL if any errors
  */
-esp_http_client_handle_t esp_http_client_init(esp_http_client_config_t *config);
+esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *config);
 
 /**
  * @brief      Invoke this function after `esp_http_client_init` and all the options calls are made, and will perform the
@@ -350,6 +351,17 @@ esp_err_t esp_http_client_close(esp_http_client_handle_t client);
  */
 esp_err_t esp_http_client_cleanup(esp_http_client_handle_t client);
 
+/**
+ * @brief      Get transport type
+ *
+ * @param[in]  client   The esp_http_client handle
+ *
+ * @return
+ *     - HTTP_TRANSPORT_UNKNOWN
+ *     - HTTP_TRANSPORT_OVER_TCP
+ *     - HTTP_TRANSPORT_OVER_SSL
+ */
+esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_handle_t client);
 
 
 #ifdef __cplusplus
@@ -357,4 +369,4 @@ esp_err_t esp_http_client_cleanup(esp_http_client_handle_t client);
 #endif
 
 
-#endif
+#endif
\ No newline at end of file
index 2ccc5013133a8ca9fa6a3cd66ba0339070139d8f..2e65888abcd06da96b4d6d445ecbe402ac2afeca 100644 (file)
@@ -63,8 +63,14 @@ char *http_utils_assign_string(char **str, const char *new_str, int len)
 
 void http_utils_trim_whitespace(char **str)
 {
-    char *end;
-    char *start = *str;
+    char *end, *start;
+    if (str == NULL) {
+        return;
+    }
+    start = *str;
+    if (start == NULL) {
+        return;
+    }
     // Trim leading space
     while (isspace((unsigned char)*start)) start ++;
 
index 8a3c49c0ffdf3f93502c5bf84f4d5b3811d3270a..bb07c92455ec7ef9d2e05ae5a35cd9bb4c948b74 100644 (file)
@@ -206,12 +206,14 @@ static int ssl_write(transport_handle_t t, const char *buffer, int len, int time
 
 static int ssl_read(transport_handle_t t, char *buffer, int len, int timeout_ms)
 {
-    int ret;
+    int poll = -1, ret;
     transport_ssl_t *ssl = transport_get_context_data(t);
-    ret = mbedtls_ssl_read(&ssl->ctx, (unsigned char *)buffer, len);
-    if (ret == 0) {
-        return -1;
+    if (mbedtls_ssl_get_bytes_avail(&ssl->ctx) <= 0) {
+        if ((poll = transport_poll_read(t, timeout_ms)) <= 0) {
+            return poll;
+        }
     }
+    ret = mbedtls_ssl_read(&ssl->ctx, (unsigned char *)buffer, len);
     return ret;
 }
 
diff --git a/components/esp_https_ota/component.mk b/components/esp_https_ota/component.mk
new file mode 100644 (file)
index 0000000..ebe80ff
--- /dev/null
@@ -0,0 +1,3 @@
+COMPONENT_SRCDIRS := src
+
+COMPONENT_ADD_INCLUDEDIRS := include
diff --git a/components/esp_https_ota/include/esp_https_ota.h b/components/esp_https_ota/include/esp_https_ota.h
new file mode 100644 (file)
index 0000000..1571956
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <esp_http_client.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief    HTTPS OTA Firmware upgrade.
+ *
+ * This function performs HTTPS OTA Firmware upgrade
+ *
+ * @param[in]  config       pointer to esp_http_client_config_t structure.
+ *
+ * @note     For secure HTTPS updates, the `cert_pem` member of `config`
+ *           structure must be set to the server certificate.
+ *
+ * @return
+ *    - ESP_OK: OTA data updated, next reboot will use specified partition.
+ *    - ESP_FAIL: For generic failure.
+ *    - ESP_ERR_OTA_VALIDATE_FAILED: Invalid app image
+ *    - ESP_ERR_NO_MEM: Cannot allocate memory for OTA operation.
+ *    - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed.
+ *    - For other return codes, refer OTA documentation in esp-idf's app_update component.
+ */
+esp_err_t esp_https_ota(const esp_http_client_config_t *config);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/components/esp_https_ota/src/esp_https_ota.c b/components/esp_https_ota/src/esp_https_ota.c
new file mode 100644 (file)
index 0000000..9929a18
--- /dev/null
@@ -0,0 +1,130 @@
+// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <esp_https_ota.h>
+#include <esp_ota_ops.h>
+#include <esp_log.h>
+
+#define OTA_BUF_SIZE 256
+static const char *TAG = "esp_https_ota";
+
+static void http_cleanup(esp_http_client_handle_t client)
+{
+    esp_http_client_close(client);
+    esp_http_client_cleanup(client);
+}
+
+esp_err_t esp_https_ota(const esp_http_client_config_t *config)
+{
+    if (!config) {
+        ESP_LOGE(TAG, "esp_http_client config not found");
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    if (!config->cert_pem) {
+        ESP_LOGE(TAG, "Server certificate not found in esp_http_client config");
+        return ESP_FAIL;
+    }
+
+    esp_http_client_handle_t client = esp_http_client_init(config);
+    if (client == NULL) {
+        ESP_LOGE(TAG, "Failed to initialise HTTP connection");
+        return ESP_FAIL;
+    }
+
+    if (esp_http_client_get_transport_type(client) != HTTP_TRANSPORT_OVER_SSL) {
+        ESP_LOGE(TAG, "Transport is not over HTTPS");
+        return ESP_FAIL;
+    }
+
+    esp_err_t err = esp_http_client_open(client, 0);
+    if (err != ESP_OK) {
+        esp_http_client_cleanup(client);
+        ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
+        return err;
+    }
+    esp_http_client_fetch_headers(client);
+
+    esp_ota_handle_t update_handle = 0;
+    const esp_partition_t *update_partition = NULL;
+    ESP_LOGI(TAG, "Starting OTA...");
+    update_partition = esp_ota_get_next_update_partition(NULL);
+    if (update_partition == NULL) {
+        ESP_LOGE(TAG, "Passive OTA partition not found");
+        http_cleanup(client);
+        return ESP_FAIL;
+    }
+    ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
+             update_partition->subtype, update_partition->address);
+
+    err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ota_begin failed, error=%d", err);
+        http_cleanup(client);
+        return err;
+    }
+    ESP_LOGI(TAG, "esp_ota_begin succeeded");
+    ESP_LOGI(TAG, "Please Wait. This may take time");
+
+    esp_err_t ota_write_err = ESP_OK;
+    char *upgrade_data_buf = (char *)malloc(OTA_BUF_SIZE);
+    if (!upgrade_data_buf) {
+        ESP_LOGE(TAG, "Couldn't allocate memory to upgrade data buffer");
+        return ESP_ERR_NO_MEM;
+    }
+    int binary_file_len = 0;
+    while (1) {
+        int data_read = esp_http_client_read(client, upgrade_data_buf, OTA_BUF_SIZE);
+        if (data_read == 0) {
+            ESP_LOGI(TAG, "Connection closed,all data received");
+            break;
+        }
+        if (data_read < 0) {
+            ESP_LOGE(TAG, "Error: SSL data read error");
+            break;
+        }
+        if (data_read > 0) {
+            ota_write_err = esp_ota_write( update_handle, (const void *)upgrade_data_buf, data_read);
+            if (ota_write_err != ESP_OK) {
+                break;
+            }
+            binary_file_len += data_read;
+            ESP_LOGD(TAG, "Written image length %d", binary_file_len);
+        }
+    }
+    free(upgrade_data_buf);
+    http_cleanup(client); 
+    ESP_LOGD(TAG, "Total binary data length writen: %d", binary_file_len);
+    
+    esp_err_t ota_end_err = esp_ota_end(update_handle);
+    if (ota_write_err != ESP_OK) {
+        ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%d", err);
+        return ota_write_err;
+    } else if (ota_end_err != ESP_OK) {
+        ESP_LOGE(TAG, "Error: esp_ota_end failed! err=0x%d. Image is invalid", ota_end_err);
+        return ota_end_err;
+    }
+
+    err = esp_ota_set_boot_partition(update_partition);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%d", err);
+        return err;
+    }
+    ESP_LOGI(TAG, "esp_ota_set_boot_partition succeeded"); 
+
+    return ESP_OK;
+}
index a1091a006a31b62ca24c57c10b5eb3d0a51a638a..321941fd1c455ecc10b7f0c73d1208519400736a 100755 (executable)
@@ -22,7 +22,7 @@ except ImportError:
     print "Esptool is not found! Set proper $IDF_PATH in environment."
     sys.exit(2)
 
-__version__ = "0.1-dev"
+__version__ = "0.2-dev"
 
 if os.name == 'nt':
     CLOSE_FDS = False
@@ -77,12 +77,6 @@ class BinStruct(object):
         keys =  self.__class__.fields
         return struct.pack(self.__class__.format, *(self.__dict__[k] for k in keys))
 
-#     def __str__(self):
-#         keys =  self.__class__.fields
-#         return (self.__class__.__name__ + "({" +
-#             ", ".join("%s:%r" % (k, self.__dict__[k]) for k in keys) +
-#             "})")
-
 
 class Elf32FileHeader(BinStruct):
     """ELF32 file header
@@ -304,14 +298,12 @@ class ESPCoreDumpElfFile(esptool.ELFFile):
             raise ESPCoreDumpError("%s does not appear to be an Xtensa ELF file. e_machine=%04x" % (self.name, machine))
         self.e_type = type
         self.e_machine = machine
+        self.sections = []
+        self.program_segments = []
         if shnum > 0:
             self._read_sections(f, shoff, shstrndx)
-        else:
-            self.sections = []
-            if phnum > 0:
-                self._read_program_segments(f, phoff, phentsize, phnum)
-            else:
-                self.program_segments = []
+        if phnum > 0:
+            self._read_program_segments(f, phoff, phentsize, phnum)
 
     def _read_sections(self, f, section_header_offs, shstrndx):
         """Reads core dump sections from ELF file
@@ -373,17 +365,15 @@ class ESPCoreDumpElfFile(esptool.ELFFile):
         def read_program_header(offs):
             type,offset,vaddr,_paddr,filesz,_memsz,flags,_align = struct.unpack_from("<LLLLLLLL", seg_table[offs:])
             return (type,offset,vaddr,filesz,flags)
-        all_segments = [read_program_header(offs) for offs in seg_table_offs]
-        prog_segments = [s for s in all_segments if s[0] == self.PT_LOAD]
+        prog_segments = [read_program_header(offs) for offs in seg_table_offs]
 
         # build the real list of ImageSegment by reading actual data for each segment from the ELF file itself
         def read_data(offs,size):
             f.seek(offs)
             return f.read(size)
 
-        prog_segments = [ESPCoreDumpSegment(vaddr, read_data(offset, filesz), type, flags) for (type, offset, vaddr, filesz,flags) in prog_segments
+        self.program_segments = [ESPCoreDumpSegment(vaddr, read_data(offset, filesz), type, flags) for (type, offset, vaddr, filesz,flags) in prog_segments
                          if vaddr != 0]
-        self.program_segments = prog_segments
 
     def add_program_segment(self, addr, data, type, flags):
         """Adds new program segment
@@ -571,7 +561,7 @@ class ESPCoreDumpLoader(object):
             if self.fcore_name:
                 self.remove_tmp_file(self.fcore_name)
 
-    def create_corefile(self, core_fname=None, off=0):
+    def create_corefile(self, core_fname=None, off=0, rom_elf=None):
         """Creates core dump ELF file
         """
         core_off = off
@@ -622,6 +612,11 @@ class ESPCoreDumpLoader(object):
 
         # add notes
         core_elf.add_program_segment(0, notes, ESPCoreDumpElfFile.PT_NOTE, 0)
+        # add ROM text sections
+        if rom_elf:
+            for ps in rom_elf.program_segments:
+                if ps.flags & ESPCoreDumpSegment.PF_X:
+                    core_elf.add_program_segment(ps.addr, ps.data, ESPCoreDumpElfFile.PT_LOAD, ps.flags)
     
         core_elf.e_type = ESPCoreDumpElfFile.ET_CORE
         core_elf.e_machine = ESPCoreDumpElfFile.EM_XTENSA
@@ -748,7 +743,7 @@ class ESPCoreDumpFlashLoader(ESPCoreDumpLoader):
             raise ESPCoreDumpLoaderError("Invalid start magic number!")
         return tot_len
 
-    def create_corefile(self, core_fname=None):
+    def create_corefile(self, core_fname=None, rom_elf=None):
         """Checks flash coredump data integrity and creates ELF file
         """
         data = self.read_data(0, self.ESP32_COREDUMP_FLASH_MAGIC_SZ)
@@ -761,7 +756,7 @@ class ESPCoreDumpFlashLoader(ESPCoreDumpLoader):
         if mag2 != self.ESP32_COREDUMP_FLASH_MAGIC_END:
             raise ESPCoreDumpLoaderError("Invalid end marker %x" % mag2)
         
-        return super(ESPCoreDumpFlashLoader, self).create_corefile(core_fname, off=self.ESP32_COREDUMP_FLASH_MAGIC_SZ)
+        return super(ESPCoreDumpFlashLoader, self).create_corefile(core_fname, off=self.ESP32_COREDUMP_FLASH_MAGIC_SZ, rom_elf=rom_elf)
 
 
 class GDBMIOutRecordHandler(object):
@@ -856,15 +851,27 @@ class GDBMIStreamConsoleHandler(GDBMIOutStreamHandler):
     """
     TAG = '~'
 
+def load_aux_elf(elf_path):
+    """ Loads auxilary ELF file and composes GDB command to read its symbols 
+    """
+    elf = None
+    sym_cmd = ''
+    if os.path.exists(elf_path):
+        elf = ESPCoreDumpElfFile(elf_path)
+        for s in elf.sections:
+            if s.name == '.text':
+                sym_cmd = 'add-symbol-file %s 0x%x' % (elf_path, s.addr)
+    return (elf, sym_cmd)
 
 def dbg_corefile(args):
     """ Command to load core dump from file or flash and run GDB debug session with it
     """
     global CLOSE_FDS
     loader = None
+    rom_elf,rom_sym_cmd = load_aux_elf(args.rom_elf)
     if not args.core:
         loader = ESPCoreDumpFlashLoader(args.off, port=args.port)
-        core_fname = loader.create_corefile(args.save_core)
+        core_fname = loader.create_corefile(args.save_core, rom_elf=rom_elf)
         if not core_fname:
             print "Failed to create corefile!"
             loader.cleanup()
@@ -873,7 +880,7 @@ def dbg_corefile(args):
         core_fname = args.core
         if args.core_format and args.core_format != 'elf':
             loader = ESPCoreDumpFileLoader(core_fname, args.core_format == 'b64')
-            core_fname = loader.create_corefile(args.save_core)
+            core_fname = loader.create_corefile(args.save_core, rom_elf=rom_elf)
             if not core_fname:
                 print "Failed to create corefile!"
                 loader.cleanup()
@@ -883,7 +890,8 @@ def dbg_corefile(args):
             bufsize = 0,
             args = [args.gdb,
                 '--nw', # ignore .gdbinit
-                '--core=%s' % core_fname, # core file
+                '--core=%s' % core_fname, # core file,
+                '-ex', rom_sym_cmd,
                 args.prog],
             stdin = None, stdout = None, stderr = None,
             close_fds = CLOSE_FDS
@@ -918,16 +926,19 @@ def info_corefile(args):
                         out_handlers[h].execute(ln)
                         break
 
-    def gdbmi_start(handlers):
+    def gdbmi_start(handlers, gdb_cmds):
+        gdb_args = [args.gdb,
+            '--quiet', # inhibit dumping info at start-up
+            '--nx', # inhibit window interface
+            '--nw', # ignore .gdbinit
+            '--interpreter=mi2', # use GDB/MI v2
+            '--core=%s' % core_fname] # core file
+        for c in gdb_cmds:
+            gdb_args += ['-ex', c]
+        gdb_args.append(args.prog)
         p = subprocess.Popen(
                 bufsize = 0,
-                args = [args.gdb,
-                    '--quiet', # inhibit dumping info at start-up
-                    '--nx', # inhibit window interface
-                    '--nw', # ignore .gdbinit
-                    '--interpreter=mi2', # use GDB/MI v2
-                    '--core=%s' % core_fname, # core file
-                    args.prog],
+                args = gdb_args,
                 stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT,
                 close_fds = CLOSE_FDS
                 )
@@ -943,16 +954,16 @@ def info_corefile(args):
             print "GDB exited (%s / %s)!" % (handlers[GDBMIResultHandler.TAG].result_class, handlers[GDBMIResultHandler.TAG].result_str)
             p.wait()
             print "Problem occured! GDB exited, restart it."
-            p = gdbmi_start(handlers)
+            p = gdbmi_start(handlers, [])
         elif handlers[GDBMIResultHandler.TAG].result_class != GDBMIResultHandler.RC_DONE:
             print "GDB/MI command failed (%s / %s)!" % (handlers[GDBMIResultHandler.TAG].result_class, handlers[GDBMIResultHandler.TAG].result_str)
         return p
 
-
     loader = None
+    rom_elf,rom_sym_cmd = load_aux_elf(args.rom_elf)
     if not args.core:
         loader = ESPCoreDumpFlashLoader(args.off, port=args.port)
-        core_fname = loader.create_corefile(args.save_core)
+        core_fname = loader.create_corefile(args.save_core, rom_elf=rom_elf)
         if not core_fname:
             print "Failed to create corefile!"
             loader.cleanup()
@@ -961,7 +972,7 @@ def info_corefile(args):
         core_fname = args.core
         if args.core_format and args.core_format != 'elf':
             loader = ESPCoreDumpFileLoader(core_fname, args.core_format == 'b64')
-            core_fname = loader.create_corefile(args.save_core)
+            core_fname = loader.create_corefile(args.save_core, rom_elf=rom_elf)
             if not core_fname:
                 print "Failed to create corefile!"
                 loader.cleanup()
@@ -1015,7 +1026,7 @@ def info_corefile(args):
     handlers = {}
     handlers[GDBMIResultHandler.TAG] = GDBMIResultHandler(verbose=False)
     handlers[GDBMIStreamConsoleHandler.TAG] = GDBMIStreamConsoleHandler(None, verbose=False)
-    p = gdbmi_start(handlers)
+    p = gdbmi_start(handlers, [rom_sym_cmd])
 
     print "==============================================================="
     print "==================== ESP32 CORE DUMP START ===================="
@@ -1033,11 +1044,21 @@ def info_corefile(args):
     for ms in merged_segs:
         print "%s 0x%x 0x%x %s" % (ms[0], ms[1], ms[2], ms[3])
     for cs in core_segs:
-        print ".coredump.tasks 0x%x 0x%x %s" % (cs.addr, len(cs.data), cs.attr_str())
+        # core dump exec segments are from ROM, other are belong to tasks (TCB or stack)
+        if cs.flags & ESPCoreDumpSegment.PF_X:
+            seg_name = 'rom.text'
+        else:
+            seg_name = 'tasks.data'
+        print ".coredump.%s 0x%x 0x%x %s" % (seg_name, cs.addr, len(cs.data), cs.attr_str())
     if args.print_mem:
         print "\n====================== CORE DUMP MEMORY CONTENTS ========================"
         for cs in core_elf.program_segments:
-            print ".coredump.tasks 0x%x 0x%x %s" % (cs.addr, len(cs.data), cs.attr_str())
+            # core dump exec segments are from ROM, other are belong to tasks (TCB or stack)
+            if cs.flags & ESPCoreDumpSegment.PF_X:
+                seg_name = 'rom.text'
+            else:
+                seg_name = 'tasks.data'
+            print ".coredump.%s 0x%x 0x%x %s" % (seg_name, cs.addr, len(cs.data), cs.attr_str())
             p = gdbmi_getinfo(p, handlers, "x/%dx 0x%x" % (len(cs.data)/4, cs.addr))
 
     print "\n===================== ESP32 CORE DUMP END ====================="
@@ -1086,6 +1107,7 @@ def main():
     parser_debug_coredump.add_argument('--core-format', '-t', help='(elf, raw or b64). File specified with "-c" is an ELF ("elf"), raw (raw) or base64-encoded (b64) binary', type=str, default='elf')
     parser_debug_coredump.add_argument('--off', '-o', help='Ofsset of coredump partition in flash (type "make partition_table" to see).', type=int, default=0x110000)
     parser_debug_coredump.add_argument('--save-core', '-s', help='Save core to file. Othwerwise temporary core file will be deleted. Ignored with "-c"', type=str)
+    parser_debug_coredump.add_argument('--rom-elf', '-r', help='Path to ROM ELF file.', type=str, default='esp32_rom.elf')
     parser_debug_coredump.add_argument('prog', help='Path to program\'s ELF binary', type=str)
 
     parser_info_coredump = subparsers.add_parser(
@@ -1096,6 +1118,7 @@ def main():
     parser_info_coredump.add_argument('--core-format', '-t', help='(elf, raw or b64). File specified with "-c" is an ELF ("elf"), raw (raw) or base64-encoded (b64) binary', type=str, default='elf')
     parser_info_coredump.add_argument('--off', '-o', help='Ofsset of coredump partition in flash (type "make partition_table" to see).', type=int, default=0x110000)
     parser_info_coredump.add_argument('--save-core', '-s', help='Save core to file. Othwerwise temporary core file will be deleted. Does not work with "-c"', type=str)
+    parser_info_coredump.add_argument('--rom-elf', '-r', help='Path to ROM ELF file.', type=str, default='esp32_rom.elf')
     parser_info_coredump.add_argument('--print-mem', '-m', help='Print memory dump', action='store_true')
     parser_info_coredump.add_argument('prog', help='Path to program\'s ELF binary', type=str)
 
diff --git a/components/expat/COPYING b/components/expat/COPYING
deleted file mode 100644 (file)
index 092c83b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper
-Copyright (c) 2001-2016 Expat maintainers
-
-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.
diff --git a/components/expat/README b/components/expat/README
deleted file mode 100644 (file)
index a7d2845..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-
-                        Expat, Release 2.2.0
-
-This is Expat, a C library for parsing XML, written by James Clark.
-Expat is a stream-oriented XML parser.  This means that you register
-handlers with the parser before starting the parse.  These handlers
-are called when the parser discovers the associated structures in the
-document being parsed.  A start tag is an example of the kind of
-structures for which you may register handlers.
-
-Windows users should use the expat_win32bin package, which includes
-both precompiled libraries and executables, and source code for
-developers.
-
-Expat is free software.  You may copy, distribute, and modify it under
-the terms of the License contained in the file COPYING distributed
-with this package.  This license is the same as the MIT/X Consortium
-license.
-
-Versions of Expat that have an odd minor version (the middle number in
-the release above), are development releases and should be considered
-as beta software.  Releases with even minor version numbers are
-intended to be production grade software.
-
-If you are building Expat from a check-out from the CVS repository,
-you need to run a script that generates the configure script using the
-GNU autoconf and libtool tools.  To do this, you need to have
-autoconf 2.58 or newer. Run the script like this:
-
-        ./buildconf.sh
-
-Once this has been done, follow the same instructions as for building
-from a source distribution.
-
-To build Expat from a source distribution, you first run the
-configuration shell script in the top level distribution directory:
-
-        ./configure
-
-There are many options which you may provide to configure (which you
-can discover by running configure with the --help option).  But the
-one of most interest is the one that sets the installation directory.
-By default, the configure script will set things up to install
-libexpat into /usr/local/lib, expat.h into /usr/local/include, and
-xmlwf into /usr/local/bin.  If, for example, you'd prefer to install
-into /home/me/mystuff/lib, /home/me/mystuff/include, and
-/home/me/mystuff/bin, you can tell configure about that with:
-
-        ./configure --prefix=/home/me/mystuff
-        
-Another interesting option is to enable 64-bit integer support for
-line and column numbers and the over-all byte index:
-
-        ./configure CPPFLAGS=-DXML_LARGE_SIZE
-        
-However, such a modification would be a breaking change to the ABI
-and is therefore not recommended for general use - e.g. as part of
-a Linux distribution - but rather for builds with special requirements.
-
-After running the configure script, the "make" command will build
-things and "make install" will install things into their proper
-location.  Have a look at the "Makefile" to learn about additional
-"make" options.  Note that you need to have write permission into
-the directories into which things will be installed.
-
-If you are interested in building Expat to provide document
-information in UTF-16 encoding rather than the default UTF-8, follow
-these instructions (after having run "make distclean"):
-
-        1. For UTF-16 output as unsigned short (and version/error
-           strings as char), run:
-
-               ./configure CPPFLAGS=-DXML_UNICODE
-
-           For UTF-16 output as wchar_t (incl. version/error strings),
-           run:
-
-               ./configure CFLAGS="-g -O2 -fshort-wchar" \
-                           CPPFLAGS=-DXML_UNICODE_WCHAR_T
-
-        2. Edit the MakeFile, changing:
-
-               LIBRARY = libexpat.la
-
-           to:
-
-               LIBRARY = libexpatw.la
-
-           (Note the additional "w" in the library name.)
-
-        3. Run "make buildlib" (which builds the library only).
-           Or, to save step 2, run "make buildlib LIBRARY=libexpatw.la".
-
-        4. Run "make installlib" (which installs the library only).
-           Or, if step 2 was omitted, run "make installlib LIBRARY=libexpatw.la".
-           
-Using DESTDIR or INSTALL_ROOT is enabled, with INSTALL_ROOT being the default
-value for DESTDIR, and the rest of the make file using only DESTDIR.
-It works as follows:
-   $ make install DESTDIR=/path/to/image
-overrides the in-makefile set DESTDIR, while both
-   $ INSTALL_ROOT=/path/to/image make install
-   $ make install INSTALL_ROOT=/path/to/image
-use DESTDIR=$(INSTALL_ROOT), even if DESTDIR eventually is defined in the
-environment, because variable-setting priority is
-1) commandline
-2) in-makefile
-3) environment  
-
-Note: This only applies to the Expat library itself, building UTF-16 versions
-of xmlwf and the tests is currently not supported.         
-
-Note for Solaris users:  The "ar" command is usually located in
-"/usr/ccs/bin", which is not in the default PATH.  You will need to
-add this to your path for the "make" command, and probably also switch
-to GNU make (the "make" found in /usr/ccs/bin does not seem to work
-properly -- apparently it does not understand .PHONY directives).  If
-you're using ksh or bash, use this command to build:
-
-        PATH=/usr/ccs/bin:$PATH make
-
-When using Expat with a project using autoconf for configuration, you
-can use the probing macro in conftools/expat.m4 to determine how to
-include Expat.  See the comments at the top of that file for more
-information.
-
-A reference manual is available in the file doc/reference.html in this
-distribution.
-
-The homepage for this project is http://www.libexpat.org/.  There
-are links there to connect you to the bug reports page.  If you need
-to report a bug when you don't have access to a browser, you may also
-send a bug report by email to expat-bugs@mail.libexpat.org.
-
-Discussion related to the direction of future expat development takes
-place on expat-discuss@mail.libexpat.org.  Archives of this list and
-other Expat-related lists may be found at:
-
-        http://mail.libexpat.org/mailman/listinfo/
index bf34d31426e767c4f6d2eb92c23af7b5fb901a29..851f6a8c38c3dcd2fd19f6b4e8317e27f73ecd8f 100644 (file)
@@ -1,10 +1,12 @@
 #
 # Component Makefile
 #
-COMPONENT_ADD_INCLUDEDIRS := port/include include/expat
+COMPONENT_ADD_INCLUDEDIRS := expat/expat/lib port/include
 
-COMPONENT_SRCDIRS := library port
+COMPONENT_SRCDIRS := expat/expat/lib port
 
-CFLAGS += -Wno-unused-function -DHAVE_EXPAT_CONFIG_H
+CFLAGS += -DHAVE_EXPAT_CONFIG_H -DHAVE_GETRANDOM
 # Temporary suppress "fallthrough" warnings until they are fixed in expat repo
 CFLAGS += -Wno-implicit-fallthrough
+
+COMPONENT_SUBMODULES += expat
diff --git a/components/expat/expat b/components/expat/expat
new file mode 160000 (submodule)
index 0000000..968b8cc
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 968b8cc46dbee47b83318d5f31a8e7907199614b
diff --git a/components/expat/include/expat/ascii.h b/components/expat/include/expat/ascii.h
deleted file mode 100644 (file)
index d10530b..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-#define ASCII_A 0x41
-#define ASCII_B 0x42
-#define ASCII_C 0x43
-#define ASCII_D 0x44
-#define ASCII_E 0x45
-#define ASCII_F 0x46
-#define ASCII_G 0x47
-#define ASCII_H 0x48
-#define ASCII_I 0x49
-#define ASCII_J 0x4A
-#define ASCII_K 0x4B
-#define ASCII_L 0x4C
-#define ASCII_M 0x4D
-#define ASCII_N 0x4E
-#define ASCII_O 0x4F
-#define ASCII_P 0x50
-#define ASCII_Q 0x51
-#define ASCII_R 0x52
-#define ASCII_S 0x53
-#define ASCII_T 0x54
-#define ASCII_U 0x55
-#define ASCII_V 0x56
-#define ASCII_W 0x57
-#define ASCII_X 0x58
-#define ASCII_Y 0x59
-#define ASCII_Z 0x5A
-
-#define ASCII_a 0x61
-#define ASCII_b 0x62
-#define ASCII_c 0x63
-#define ASCII_d 0x64
-#define ASCII_e 0x65
-#define ASCII_f 0x66
-#define ASCII_g 0x67
-#define ASCII_h 0x68
-#define ASCII_i 0x69
-#define ASCII_j 0x6A
-#define ASCII_k 0x6B
-#define ASCII_l 0x6C
-#define ASCII_m 0x6D
-#define ASCII_n 0x6E
-#define ASCII_o 0x6F
-#define ASCII_p 0x70
-#define ASCII_q 0x71
-#define ASCII_r 0x72
-#define ASCII_s 0x73
-#define ASCII_t 0x74
-#define ASCII_u 0x75
-#define ASCII_v 0x76
-#define ASCII_w 0x77
-#define ASCII_x 0x78
-#define ASCII_y 0x79
-#define ASCII_z 0x7A
-
-#define ASCII_0 0x30
-#define ASCII_1 0x31
-#define ASCII_2 0x32
-#define ASCII_3 0x33
-#define ASCII_4 0x34
-#define ASCII_5 0x35
-#define ASCII_6 0x36
-#define ASCII_7 0x37
-#define ASCII_8 0x38
-#define ASCII_9 0x39
-
-#define ASCII_TAB 0x09
-#define ASCII_SPACE 0x20
-#define ASCII_EXCL 0x21
-#define ASCII_QUOT 0x22
-#define ASCII_AMP 0x26
-#define ASCII_APOS 0x27
-#define ASCII_MINUS 0x2D
-#define ASCII_PERIOD 0x2E
-#define ASCII_COLON 0x3A
-#define ASCII_SEMI 0x3B
-#define ASCII_LT 0x3C
-#define ASCII_EQUALS 0x3D
-#define ASCII_GT 0x3E
-#define ASCII_LSQB 0x5B
-#define ASCII_RSQB 0x5D
-#define ASCII_UNDERSCORE 0x5F
-#define ASCII_LPAREN 0x28
-#define ASCII_RPAREN 0x29
-#define ASCII_FF 0x0C
-#define ASCII_SLASH 0x2F
-#define ASCII_HASH 0x23
-#define ASCII_PIPE 0x7C
-#define ASCII_COMMA 0x2C
diff --git a/components/expat/include/expat/asciitab.h b/components/expat/include/expat/asciitab.h
deleted file mode 100644 (file)
index 79a15c2..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
-/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
-/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
-/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
-/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
-/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
-/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
-/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
-/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
-/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
-/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/components/expat/include/expat/expat.h b/components/expat/include/expat/expat.h
deleted file mode 100644 (file)
index 086e24b..0000000
+++ /dev/null
@@ -1,1048 +0,0 @@
-/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-#ifndef Expat_INCLUDED
-#define Expat_INCLUDED 1
-
-#ifdef __VMS
-/*      0        1         2         3      0        1         2         3
-        1234567890123456789012345678901     1234567890123456789012345678901 */
-#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler
-#define XML_SetUnparsedEntityDeclHandler    XML_SetUnparsedEntDeclHandler
-#define XML_SetStartNamespaceDeclHandler    XML_SetStartNamespcDeclHandler
-#define XML_SetExternalEntityRefHandlerArg  XML_SetExternalEntRefHandlerArg
-#endif
-
-#include <stdlib.h>
-#include "expat_external.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct XML_ParserStruct;
-typedef struct XML_ParserStruct *XML_Parser;
-
-/* Should this be defined using stdbool.h when C99 is available? */
-typedef unsigned char XML_Bool;
-#define XML_TRUE   ((XML_Bool) 1)
-#define XML_FALSE  ((XML_Bool) 0)
-
-/* The XML_Status enum gives the possible return values for several
-   API functions.  The preprocessor #defines are included so this
-   stanza can be added to code that still needs to support older
-   versions of Expat 1.95.x:
-
-   #ifndef XML_STATUS_OK
-   #define XML_STATUS_OK    1
-   #define XML_STATUS_ERROR 0
-   #endif
-
-   Otherwise, the #define hackery is quite ugly and would have been
-   dropped.
-*/
-enum XML_Status {
-  XML_STATUS_ERROR = 0,
-#define XML_STATUS_ERROR XML_STATUS_ERROR
-  XML_STATUS_OK = 1,
-#define XML_STATUS_OK XML_STATUS_OK
-  XML_STATUS_SUSPENDED = 2
-#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED
-};
-
-enum XML_Error {
-  XML_ERROR_NONE,
-  XML_ERROR_NO_MEMORY,
-  XML_ERROR_SYNTAX,
-  XML_ERROR_NO_ELEMENTS,
-  XML_ERROR_INVALID_TOKEN,
-  XML_ERROR_UNCLOSED_TOKEN,
-  XML_ERROR_PARTIAL_CHAR,
-  XML_ERROR_TAG_MISMATCH,
-  XML_ERROR_DUPLICATE_ATTRIBUTE,
-  XML_ERROR_JUNK_AFTER_DOC_ELEMENT,
-  XML_ERROR_PARAM_ENTITY_REF,
-  XML_ERROR_UNDEFINED_ENTITY,
-  XML_ERROR_RECURSIVE_ENTITY_REF,
-  XML_ERROR_ASYNC_ENTITY,
-  XML_ERROR_BAD_CHAR_REF,
-  XML_ERROR_BINARY_ENTITY_REF,
-  XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF,
-  XML_ERROR_MISPLACED_XML_PI,
-  XML_ERROR_UNKNOWN_ENCODING,
-  XML_ERROR_INCORRECT_ENCODING,
-  XML_ERROR_UNCLOSED_CDATA_SECTION,
-  XML_ERROR_EXTERNAL_ENTITY_HANDLING,
-  XML_ERROR_NOT_STANDALONE,
-  XML_ERROR_UNEXPECTED_STATE,
-  XML_ERROR_ENTITY_DECLARED_IN_PE,
-  XML_ERROR_FEATURE_REQUIRES_XML_DTD,
-  XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING,
-  /* Added in 1.95.7. */
-  XML_ERROR_UNBOUND_PREFIX,
-  /* Added in 1.95.8. */
-  XML_ERROR_UNDECLARING_PREFIX,
-  XML_ERROR_INCOMPLETE_PE,
-  XML_ERROR_XML_DECL,
-  XML_ERROR_TEXT_DECL,
-  XML_ERROR_PUBLICID,
-  XML_ERROR_SUSPENDED,
-  XML_ERROR_NOT_SUSPENDED,
-  XML_ERROR_ABORTED,
-  XML_ERROR_FINISHED,
-  XML_ERROR_SUSPEND_PE,
-  /* Added in 2.0. */
-  XML_ERROR_RESERVED_PREFIX_XML,
-  XML_ERROR_RESERVED_PREFIX_XMLNS,
-  XML_ERROR_RESERVED_NAMESPACE_URI
-};
-
-enum XML_Content_Type {
-  XML_CTYPE_EMPTY = 1,
-  XML_CTYPE_ANY,
-  XML_CTYPE_MIXED,
-  XML_CTYPE_NAME,
-  XML_CTYPE_CHOICE,
-  XML_CTYPE_SEQ
-};
-
-enum XML_Content_Quant {
-  XML_CQUANT_NONE,
-  XML_CQUANT_OPT,
-  XML_CQUANT_REP,
-  XML_CQUANT_PLUS
-};
-
-/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be
-   XML_CQUANT_NONE, and the other fields will be zero or NULL.
-   If type == XML_CTYPE_MIXED, then quant will be NONE or REP and
-   numchildren will contain number of elements that may be mixed in
-   and children point to an array of XML_Content cells that will be
-   all of XML_CTYPE_NAME type with no quantification.
-
-   If type == XML_CTYPE_NAME, then the name points to the name, and
-   the numchildren field will be zero and children will be NULL. The
-   quant fields indicates any quantifiers placed on the name.
-
-   CHOICE and SEQ will have name NULL, the number of children in
-   numchildren and children will point, recursively, to an array
-   of XML_Content cells.
-
-   The EMPTY, ANY, and MIXED types will only occur at top level.
-*/
-
-typedef struct XML_cp XML_Content;
-
-struct XML_cp {
-  enum XML_Content_Type         type;
-  enum XML_Content_Quant        quant;
-  XML_Char *                    name;
-  unsigned int                  numchildren;
-  XML_Content *                 children;
-};
-
-
-/* This is called for an element declaration. See above for
-   description of the model argument. It's the caller's responsibility
-   to free model when finished with it.
-*/
-typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData,
-                                                const XML_Char *name,
-                                                XML_Content *model);
-
-XMLPARSEAPI(void)
-XML_SetElementDeclHandler(XML_Parser parser,
-                          XML_ElementDeclHandler eldecl);
-
-/* The Attlist declaration handler is called for *each* attribute. So
-   a single Attlist declaration with multiple attributes declared will
-   generate multiple calls to this handler. The "default" parameter
-   may be NULL in the case of the "#IMPLIED" or "#REQUIRED"
-   keyword. The "isrequired" parameter will be true and the default
-   value will be NULL in the case of "#REQUIRED". If "isrequired" is
-   true and default is non-NULL, then this is a "#FIXED" default.
-*/
-typedef void (XMLCALL *XML_AttlistDeclHandler) (
-                                    void            *userData,
-                                    const XML_Char  *elname,
-                                    const XML_Char  *attname,
-                                    const XML_Char  *att_type,
-                                    const XML_Char  *dflt,
-                                    int              isrequired);
-
-XMLPARSEAPI(void)
-XML_SetAttlistDeclHandler(XML_Parser parser,
-                          XML_AttlistDeclHandler attdecl);
-
-/* The XML declaration handler is called for *both* XML declarations
-   and text declarations. The way to distinguish is that the version
-   parameter will be NULL for text declarations. The encoding
-   parameter may be NULL for XML declarations. The standalone
-   parameter will be -1, 0, or 1 indicating respectively that there
-   was no standalone parameter in the declaration, that it was given
-   as no, or that it was given as yes.
-*/
-typedef void (XMLCALL *XML_XmlDeclHandler) (void           *userData,
-                                            const XML_Char *version,
-                                            const XML_Char *encoding,
-                                            int             standalone);
-
-XMLPARSEAPI(void)
-XML_SetXmlDeclHandler(XML_Parser parser,
-                      XML_XmlDeclHandler xmldecl);
-
-
-typedef struct {
-  void *(*malloc_fcn)(size_t size);
-  void *(*realloc_fcn)(void *ptr, size_t size);
-  void (*free_fcn)(void *ptr);
-} XML_Memory_Handling_Suite;
-
-/* Constructs a new parser; encoding is the encoding specified by the
-   external protocol or NULL if there is none specified.
-*/
-XMLPARSEAPI(XML_Parser)
-XML_ParserCreate(const XML_Char *encoding);
-
-/* Constructs a new parser and namespace processor.  Element type
-   names and attribute names that belong to a namespace will be
-   expanded; unprefixed attribute names are never expanded; unprefixed
-   element type names are expanded only if there is a default
-   namespace. The expanded name is the concatenation of the namespace
-   URI, the namespace separator character, and the local part of the
-   name.  If the namespace separator is '\0' then the namespace URI
-   and the local part will be concatenated without any separator.
-   It is a programming error to use the separator '\0' with namespace
-   triplets (see XML_SetReturnNSTriplet).
-*/
-XMLPARSEAPI(XML_Parser)
-XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
-
-
-/* Constructs a new parser using the memory management suite referred to
-   by memsuite. If memsuite is NULL, then use the standard library memory
-   suite. If namespaceSeparator is non-NULL it creates a parser with
-   namespace processing as described above. The character pointed at
-   will serve as the namespace separator.
-
-   All further memory operations used for the created parser will come from
-   the given suite.
-*/
-XMLPARSEAPI(XML_Parser)
-XML_ParserCreate_MM(const XML_Char *encoding,
-                    const XML_Memory_Handling_Suite *memsuite,
-                    const XML_Char *namespaceSeparator);
-
-/* Prepare a parser object to be re-used.  This is particularly
-   valuable when memory allocation overhead is disproportionatly high,
-   such as when a large number of small documnents need to be parsed.
-   All handlers are cleared from the parser, except for the
-   unknownEncodingHandler. The parser's external state is re-initialized
-   except for the values of ns and ns_triplets.
-
-   Added in Expat 1.95.3.
-*/
-XMLPARSEAPI(XML_Bool)
-XML_ParserReset(XML_Parser parser, const XML_Char *encoding);
-
-/* atts is array of name/value pairs, terminated by 0;
-   names and values are 0 terminated.
-*/
-typedef void (XMLCALL *XML_StartElementHandler) (void *userData,
-                                                 const XML_Char *name,
-                                                 const XML_Char **atts);
-
-typedef void (XMLCALL *XML_EndElementHandler) (void *userData,
-                                               const XML_Char *name);
-
-
-/* s is not 0 terminated. */
-typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData,
-                                                  const XML_Char *s,
-                                                  int len);
-
-/* target and data are 0 terminated */
-typedef void (XMLCALL *XML_ProcessingInstructionHandler) (
-                                                void *userData,
-                                                const XML_Char *target,
-                                                const XML_Char *data);
-
-/* data is 0 terminated */
-typedef void (XMLCALL *XML_CommentHandler) (void *userData,
-                                            const XML_Char *data);
-
-typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData);
-typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData);
-
-/* This is called for any characters in the XML document for which
-   there is no applicable handler.  This includes both characters that
-   are part of markup which is of a kind that is not reported
-   (comments, markup declarations), or characters that are part of a
-   construct which could be reported but for which no handler has been
-   supplied. The characters are passed exactly as they were in the XML
-   document except that they will be encoded in UTF-8 or UTF-16.
-   Line boundaries are not normalized. Note that a byte order mark
-   character is not passed to the default handler. There are no
-   guarantees about how characters are divided between calls to the
-   default handler: for example, a comment might be split between
-   multiple calls.
-*/
-typedef void (XMLCALL *XML_DefaultHandler) (void *userData,
-                                            const XML_Char *s,
-                                            int len);
-
-/* This is called for the start of the DOCTYPE declaration, before
-   any DTD or internal subset is parsed.
-*/
-typedef void (XMLCALL *XML_StartDoctypeDeclHandler) (
-                                            void *userData,
-                                            const XML_Char *doctypeName,
-                                            const XML_Char *sysid,
-                                            const XML_Char *pubid,
-                                            int has_internal_subset);
-
-/* This is called for the start of the DOCTYPE declaration when the
-   closing > is encountered, but after processing any external
-   subset.
-*/
-typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
-
-/* This is called for entity declarations. The is_parameter_entity
-   argument will be non-zero if the entity is a parameter entity, zero
-   otherwise.
-
-   For internal entities (<!ENTITY foo "bar">), value will
-   be non-NULL and systemId, publicID, and notationName will be NULL.
-   The value string is NOT nul-terminated; the length is provided in
-   the value_length argument. Since it is legal to have zero-length
-   values, do not use this argument to test for internal entities.
-
-   For external entities, value will be NULL and systemId will be
-   non-NULL. The publicId argument will be NULL unless a public
-   identifier was provided. The notationName argument will have a
-   non-NULL value only for unparsed entity declarations.
-
-   Note that is_parameter_entity can't be changed to XML_Bool, since
-   that would break binary compatibility.
-*/
-typedef void (XMLCALL *XML_EntityDeclHandler) (
-                              void *userData,
-                              const XML_Char *entityName,
-                              int is_parameter_entity,
-                              const XML_Char *value,
-                              int value_length,
-                              const XML_Char *base,
-                              const XML_Char *systemId,
-                              const XML_Char *publicId,
-                              const XML_Char *notationName);
-
-XMLPARSEAPI(void)
-XML_SetEntityDeclHandler(XML_Parser parser,
-                         XML_EntityDeclHandler handler);
-
-/* OBSOLETE -- OBSOLETE -- OBSOLETE
-   This handler has been superseded by the EntityDeclHandler above.
-   It is provided here for backward compatibility.
-
-   This is called for a declaration of an unparsed (NDATA) entity.
-   The base argument is whatever was set by XML_SetBase. The
-   entityName, systemId and notationName arguments will never be
-   NULL. The other arguments may be.
-*/
-typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) (
-                                    void *userData,
-                                    const XML_Char *entityName,
-                                    const XML_Char *base,
-                                    const XML_Char *systemId,
-                                    const XML_Char *publicId,
-                                    const XML_Char *notationName);
-
-/* This is called for a declaration of notation.  The base argument is
-   whatever was set by XML_SetBase. The notationName will never be
-   NULL.  The other arguments can be.
-*/
-typedef void (XMLCALL *XML_NotationDeclHandler) (
-                                    void *userData,
-                                    const XML_Char *notationName,
-                                    const XML_Char *base,
-                                    const XML_Char *systemId,
-                                    const XML_Char *publicId);
-
-/* When namespace processing is enabled, these are called once for
-   each namespace declaration. The call to the start and end element
-   handlers occur between the calls to the start and end namespace
-   declaration handlers. For an xmlns attribute, prefix will be
-   NULL.  For an xmlns="" attribute, uri will be NULL.
-*/
-typedef void (XMLCALL *XML_StartNamespaceDeclHandler) (
-                                    void *userData,
-                                    const XML_Char *prefix,
-                                    const XML_Char *uri);
-
-typedef void (XMLCALL *XML_EndNamespaceDeclHandler) (
-                                    void *userData,
-                                    const XML_Char *prefix);
-
-/* This is called if the document is not standalone, that is, it has an
-   external subset or a reference to a parameter entity, but does not
-   have standalone="yes". If this handler returns XML_STATUS_ERROR,
-   then processing will not continue, and the parser will return a
-   XML_ERROR_NOT_STANDALONE error.
-   If parameter entity parsing is enabled, then in addition to the
-   conditions above this handler will only be called if the referenced
-   entity was actually read.
-*/
-typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData);
-
-/* This is called for a reference to an external parsed general
-   entity.  The referenced entity is not automatically parsed.  The
-   application can parse it immediately or later using
-   XML_ExternalEntityParserCreate.
-
-   The parser argument is the parser parsing the entity containing the
-   reference; it can be passed as the parser argument to
-   XML_ExternalEntityParserCreate.  The systemId argument is the
-   system identifier as specified in the entity declaration; it will
-   not be NULL.
-
-   The base argument is the system identifier that should be used as
-   the base for resolving systemId if systemId was relative; this is
-   set by XML_SetBase; it may be NULL.
-
-   The publicId argument is the public identifier as specified in the
-   entity declaration, or NULL if none was specified; the whitespace
-   in the public identifier will have been normalized as required by
-   the XML spec.
-
-   The context argument specifies the parsing context in the format
-   expected by the context argument to XML_ExternalEntityParserCreate;
-   context is valid only until the handler returns, so if the
-   referenced entity is to be parsed later, it must be copied.
-   context is NULL only when the entity is a parameter entity.
-
-   The handler should return XML_STATUS_ERROR if processing should not
-   continue because of a fatal error in the handling of the external
-   entity.  In this case the calling parser will return an
-   XML_ERROR_EXTERNAL_ENTITY_HANDLING error.
-
-   Note that unlike other handlers the first argument is the parser,
-   not userData.
-*/
-typedef int (XMLCALL *XML_ExternalEntityRefHandler) (
-                                    XML_Parser parser,
-                                    const XML_Char *context,
-                                    const XML_Char *base,
-                                    const XML_Char *systemId,
-                                    const XML_Char *publicId);
-
-/* This is called in two situations:
-   1) An entity reference is encountered for which no declaration
-      has been read *and* this is not an error.
-   2) An internal entity reference is read, but not expanded, because
-      XML_SetDefaultHandler has been called.
-   Note: skipped parameter entities in declarations and skipped general
-         entities in attribute values cannot be reported, because
-         the event would be out of sync with the reporting of the
-         declarations or attribute values
-*/
-typedef void (XMLCALL *XML_SkippedEntityHandler) (
-                                    void *userData,
-                                    const XML_Char *entityName,
-                                    int is_parameter_entity);
-
-/* This structure is filled in by the XML_UnknownEncodingHandler to
-   provide information to the parser about encodings that are unknown
-   to the parser.
-
-   The map[b] member gives information about byte sequences whose
-   first byte is b.
-
-   If map[b] is c where c is >= 0, then b by itself encodes the
-   Unicode scalar value c.
-
-   If map[b] is -1, then the byte sequence is malformed.
-
-   If map[b] is -n, where n >= 2, then b is the first byte of an
-   n-byte sequence that encodes a single Unicode scalar value.
-
-   The data member will be passed as the first argument to the convert
-   function.
-
-   The convert function is used to convert multibyte sequences; s will
-   point to a n-byte sequence where map[(unsigned char)*s] == -n.  The
-   convert function must return the Unicode scalar value represented
-   by this byte sequence or -1 if the byte sequence is malformed.
-
-   The convert function may be NULL if the encoding is a single-byte
-   encoding, that is if map[b] >= -1 for all bytes b.
-
-   When the parser is finished with the encoding, then if release is
-   not NULL, it will call release passing it the data member; once
-   release has been called, the convert function will not be called
-   again.
-
-   Expat places certain restrictions on the encodings that are supported
-   using this mechanism.
-
-   1. Every ASCII character that can appear in a well-formed XML document,
-      other than the characters
-
-      $@\^`{}~
-
-      must be represented by a single byte, and that byte must be the
-      same byte that represents that character in ASCII.
-
-   2. No character may require more than 4 bytes to encode.
-
-   3. All characters encoded must have Unicode scalar values <=
-      0xFFFF, (i.e., characters that would be encoded by surrogates in
-      UTF-16 are  not allowed).  Note that this restriction doesn't
-      apply to the built-in support for UTF-8 and UTF-16.
-
-   4. No Unicode character may be encoded by more than one distinct
-      sequence of bytes.
-*/
-typedef struct {
-  int map[256];
-  void *data;
-  int (XMLCALL *convert)(void *data, const char *s);
-  void (XMLCALL *release)(void *data);
-} XML_Encoding;
-
-/* This is called for an encoding that is unknown to the parser.
-
-   The encodingHandlerData argument is that which was passed as the
-   second argument to XML_SetUnknownEncodingHandler.
-
-   The name argument gives the name of the encoding as specified in
-   the encoding declaration.
-
-   If the callback can provide information about the encoding, it must
-   fill in the XML_Encoding structure, and return XML_STATUS_OK.
-   Otherwise it must return XML_STATUS_ERROR.
-
-   If info does not describe a suitable encoding, then the parser will
-   return an XML_UNKNOWN_ENCODING error.
-*/
-typedef int (XMLCALL *XML_UnknownEncodingHandler) (
-                                    void *encodingHandlerData,
-                                    const XML_Char *name,
-                                    XML_Encoding *info);
-
-XMLPARSEAPI(void)
-XML_SetElementHandler(XML_Parser parser,
-                      XML_StartElementHandler start,
-                      XML_EndElementHandler end);
-
-XMLPARSEAPI(void)
-XML_SetStartElementHandler(XML_Parser parser,
-                           XML_StartElementHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetEndElementHandler(XML_Parser parser,
-                         XML_EndElementHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetCharacterDataHandler(XML_Parser parser,
-                            XML_CharacterDataHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetProcessingInstructionHandler(XML_Parser parser,
-                                    XML_ProcessingInstructionHandler handler);
-XMLPARSEAPI(void)
-XML_SetCommentHandler(XML_Parser parser,
-                      XML_CommentHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetCdataSectionHandler(XML_Parser parser,
-                           XML_StartCdataSectionHandler start,
-                           XML_EndCdataSectionHandler end);
-
-XMLPARSEAPI(void)
-XML_SetStartCdataSectionHandler(XML_Parser parser,
-                                XML_StartCdataSectionHandler start);
-
-XMLPARSEAPI(void)
-XML_SetEndCdataSectionHandler(XML_Parser parser,
-                              XML_EndCdataSectionHandler end);
-
-/* This sets the default handler and also inhibits expansion of
-   internal entities. These entity references will be passed to the
-   default handler, or to the skipped entity handler, if one is set.
-*/
-XMLPARSEAPI(void)
-XML_SetDefaultHandler(XML_Parser parser,
-                      XML_DefaultHandler handler);
-
-/* This sets the default handler but does not inhibit expansion of
-   internal entities.  The entity reference will not be passed to the
-   default handler.
-*/
-XMLPARSEAPI(void)
-XML_SetDefaultHandlerExpand(XML_Parser parser,
-                            XML_DefaultHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetDoctypeDeclHandler(XML_Parser parser,
-                          XML_StartDoctypeDeclHandler start,
-                          XML_EndDoctypeDeclHandler end);
-
-XMLPARSEAPI(void)
-XML_SetStartDoctypeDeclHandler(XML_Parser parser,
-                               XML_StartDoctypeDeclHandler start);
-
-XMLPARSEAPI(void)
-XML_SetEndDoctypeDeclHandler(XML_Parser parser,
-                             XML_EndDoctypeDeclHandler end);
-
-XMLPARSEAPI(void)
-XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
-                                 XML_UnparsedEntityDeclHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetNotationDeclHandler(XML_Parser parser,
-                           XML_NotationDeclHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetNamespaceDeclHandler(XML_Parser parser,
-                            XML_StartNamespaceDeclHandler start,
-                            XML_EndNamespaceDeclHandler end);
-
-XMLPARSEAPI(void)
-XML_SetStartNamespaceDeclHandler(XML_Parser parser,
-                                 XML_StartNamespaceDeclHandler start);
-
-XMLPARSEAPI(void)
-XML_SetEndNamespaceDeclHandler(XML_Parser parser,
-                               XML_EndNamespaceDeclHandler end);
-
-XMLPARSEAPI(void)
-XML_SetNotStandaloneHandler(XML_Parser parser,
-                            XML_NotStandaloneHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetExternalEntityRefHandler(XML_Parser parser,
-                                XML_ExternalEntityRefHandler handler);
-
-/* If a non-NULL value for arg is specified here, then it will be
-   passed as the first argument to the external entity ref handler
-   instead of the parser object.
-*/
-XMLPARSEAPI(void)
-XML_SetExternalEntityRefHandlerArg(XML_Parser parser,
-                                   void *arg);
-
-XMLPARSEAPI(void)
-XML_SetSkippedEntityHandler(XML_Parser parser,
-                            XML_SkippedEntityHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetUnknownEncodingHandler(XML_Parser parser,
-                              XML_UnknownEncodingHandler handler,
-                              void *encodingHandlerData);
-
-/* This can be called within a handler for a start element, end
-   element, processing instruction or character data.  It causes the
-   corresponding markup to be passed to the default handler.
-*/
-XMLPARSEAPI(void)
-XML_DefaultCurrent(XML_Parser parser);
-
-/* If do_nst is non-zero, and namespace processing is in effect, and
-   a name has a prefix (i.e. an explicit namespace qualifier) then
-   that name is returned as a triplet in a single string separated by
-   the separator character specified when the parser was created: URI
-   + sep + local_name + sep + prefix.
-
-   If do_nst is zero, then namespace information is returned in the
-   default manner (URI + sep + local_name) whether or not the name
-   has a prefix.
-
-   Note: Calling XML_SetReturnNSTriplet after XML_Parse or
-     XML_ParseBuffer has no effect.
-*/
-
-XMLPARSEAPI(void)
-XML_SetReturnNSTriplet(XML_Parser parser, int do_nst);
-
-/* This value is passed as the userData argument to callbacks. */
-XMLPARSEAPI(void)
-XML_SetUserData(XML_Parser parser, void *userData);
-
-/* Returns the last value set by XML_SetUserData or NULL. */
-#define XML_GetUserData(parser) (*(void **)(parser))
-
-/* This is equivalent to supplying an encoding argument to
-   XML_ParserCreate. On success XML_SetEncoding returns non-zero,
-   zero otherwise.
-   Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer
-     has no effect and returns XML_STATUS_ERROR.
-*/
-XMLPARSEAPI(enum XML_Status)
-XML_SetEncoding(XML_Parser parser, const XML_Char *encoding);
-
-/* If this function is called, then the parser will be passed as the
-   first argument to callbacks instead of userData.  The userData will
-   still be accessible using XML_GetUserData.
-*/
-XMLPARSEAPI(void)
-XML_UseParserAsHandlerArg(XML_Parser parser);
-
-/* If useDTD == XML_TRUE is passed to this function, then the parser
-   will assume that there is an external subset, even if none is
-   specified in the document. In such a case the parser will call the
-   externalEntityRefHandler with a value of NULL for the systemId
-   argument (the publicId and context arguments will be NULL as well).
-   Note: For the purpose of checking WFC: Entity Declared, passing
-     useDTD == XML_TRUE will make the parser behave as if the document
-     had a DTD with an external subset.
-   Note: If this function is called, then this must be done before
-     the first call to XML_Parse or XML_ParseBuffer, since it will
-     have no effect after that.  Returns
-     XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING.
-   Note: If the document does not have a DOCTYPE declaration at all,
-     then startDoctypeDeclHandler and endDoctypeDeclHandler will not
-     be called, despite an external subset being parsed.
-   Note: If XML_DTD is not defined when Expat is compiled, returns
-     XML_ERROR_FEATURE_REQUIRES_XML_DTD.
-*/
-XMLPARSEAPI(enum XML_Error)
-XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
-
-
-/* Sets the base to be used for resolving relative URIs in system
-   identifiers in declarations.  Resolving relative identifiers is
-   left to the application: this value will be passed through as the
-   base argument to the XML_ExternalEntityRefHandler,
-   XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base
-   argument will be copied.  Returns XML_STATUS_ERROR if out of memory,
-   XML_STATUS_OK otherwise.
-*/
-XMLPARSEAPI(enum XML_Status)
-XML_SetBase(XML_Parser parser, const XML_Char *base);
-
-XMLPARSEAPI(const XML_Char *)
-XML_GetBase(XML_Parser parser);
-
-/* Returns the number of the attribute/value pairs passed in last call
-   to the XML_StartElementHandler that were specified in the start-tag
-   rather than defaulted. Each attribute/value pair counts as 2; thus
-   this correspondds to an index into the atts array passed to the
-   XML_StartElementHandler.
-*/
-XMLPARSEAPI(int)
-XML_GetSpecifiedAttributeCount(XML_Parser parser);
-
-/* Returns the index of the ID attribute passed in the last call to
-   XML_StartElementHandler, or -1 if there is no ID attribute.  Each
-   attribute/value pair counts as 2; thus this correspondds to an
-   index into the atts array passed to the XML_StartElementHandler.
-*/
-XMLPARSEAPI(int)
-XML_GetIdAttributeIndex(XML_Parser parser);
-
-#ifdef XML_ATTR_INFO
-/* Source file byte offsets for the start and end of attribute names and values.
-   The value indices are exclusive of surrounding quotes; thus in a UTF-8 source
-   file an attribute value of "blah" will yield:
-   info->valueEnd - info->valueStart = 4 bytes.
-*/
-typedef struct {
-  XML_Index  nameStart;  /* Offset to beginning of the attribute name. */
-  XML_Index  nameEnd;    /* Offset after the attribute name's last byte. */
-  XML_Index  valueStart; /* Offset to beginning of the attribute value. */
-  XML_Index  valueEnd;   /* Offset after the attribute value's last byte. */
-} XML_AttrInfo;
-
-/* Returns an array of XML_AttrInfo structures for the attribute/value pairs
-   passed in last call to the XML_StartElementHandler that were specified
-   in the start-tag rather than defaulted. Each attribute/value pair counts
-   as 1; thus the number of entries in the array is
-   XML_GetSpecifiedAttributeCount(parser) / 2.
-*/
-XMLPARSEAPI(const XML_AttrInfo *)
-XML_GetAttributeInfo(XML_Parser parser);
-#endif
-
-/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is
-   detected.  The last call to XML_Parse must have isFinal true; len
-   may be zero for this call (or any other).
-
-   Though the return values for these functions has always been
-   described as a Boolean value, the implementation, at least for the
-   1.95.x series, has always returned exactly one of the XML_Status
-   values.
-*/
-XMLPARSEAPI(enum XML_Status)
-XML_Parse(XML_Parser parser, const char *s, int len, int isFinal);
-
-XMLPARSEAPI(void *)
-XML_GetBuffer(XML_Parser parser, int len);
-
-XMLPARSEAPI(enum XML_Status)
-XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
-
-/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return.
-   Must be called from within a call-back handler, except when aborting
-   (resumable = 0) an already suspended parser. Some call-backs may
-   still follow because they would otherwise get lost. Examples:
-   - endElementHandler() for empty elements when stopped in
-     startElementHandler(), 
-   - endNameSpaceDeclHandler() when stopped in endElementHandler(), 
-   and possibly others.
-
-   Can be called from most handlers, including DTD related call-backs,
-   except when parsing an external parameter entity and resumable != 0.
-   Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise.
-   Possible error codes: 
-   - XML_ERROR_SUSPENDED: when suspending an already suspended parser.
-   - XML_ERROR_FINISHED: when the parser has already finished.
-   - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE.
-
-   When resumable != 0 (true) then parsing is suspended, that is, 
-   XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. 
-   Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer()
-   return XML_STATUS_ERROR with error code XML_ERROR_ABORTED.
-
-   *Note*:
-   This will be applied to the current parser instance only, that is, if
-   there is a parent parser then it will continue parsing when the
-   externalEntityRefHandler() returns. It is up to the implementation of
-   the externalEntityRefHandler() to call XML_StopParser() on the parent
-   parser (recursively), if one wants to stop parsing altogether.
-
-   When suspended, parsing can be resumed by calling XML_ResumeParser(). 
-*/
-XMLPARSEAPI(enum XML_Status)
-XML_StopParser(XML_Parser parser, XML_Bool resumable);
-
-/* Resumes parsing after it has been suspended with XML_StopParser().
-   Must not be called from within a handler call-back. Returns same
-   status codes as XML_Parse() or XML_ParseBuffer().
-   Additional error code XML_ERROR_NOT_SUSPENDED possible.   
-
-   *Note*:
-   This must be called on the most deeply nested child parser instance
-   first, and on its parent parser only after the child parser has finished,
-   to be applied recursively until the document entity's parser is restarted.
-   That is, the parent parser will not resume by itself and it is up to the
-   application to call XML_ResumeParser() on it at the appropriate moment.
-*/
-XMLPARSEAPI(enum XML_Status)
-XML_ResumeParser(XML_Parser parser);
-
-enum XML_Parsing {
-  XML_INITIALIZED,
-  XML_PARSING,
-  XML_FINISHED,
-  XML_SUSPENDED
-};
-
-typedef struct {
-  enum XML_Parsing parsing;
-  XML_Bool finalBuffer;
-} XML_ParsingStatus;
-
-/* Returns status of parser with respect to being initialized, parsing,
-   finished, or suspended and processing the final buffer.
-   XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus,
-   XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED
-*/
-XMLPARSEAPI(void)
-XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status);
-
-/* Creates an XML_Parser object that can parse an external general
-   entity; context is a '\0'-terminated string specifying the parse
-   context; encoding is a '\0'-terminated string giving the name of
-   the externally specified encoding, or NULL if there is no
-   externally specified encoding.  The context string consists of a
-   sequence of tokens separated by formfeeds (\f); a token consisting
-   of a name specifies that the general entity of the name is open; a
-   token of the form prefix=uri specifies the namespace for a
-   particular prefix; a token of the form =uri specifies the default
-   namespace.  This can be called at any point after the first call to
-   an ExternalEntityRefHandler so longer as the parser has not yet
-   been freed.  The new parser is completely independent and may
-   safely be used in a separate thread.  The handlers and userData are
-   initialized from the parser argument.  Returns NULL if out of memory.
-   Otherwise returns a new XML_Parser object.
-*/
-XMLPARSEAPI(XML_Parser)
-XML_ExternalEntityParserCreate(XML_Parser parser,
-                               const XML_Char *context,
-                               const XML_Char *encoding);
-
-enum XML_ParamEntityParsing {
-  XML_PARAM_ENTITY_PARSING_NEVER,
-  XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE,
-  XML_PARAM_ENTITY_PARSING_ALWAYS
-};
-
-/* Controls parsing of parameter entities (including the external DTD
-   subset). If parsing of parameter entities is enabled, then
-   references to external parameter entities (including the external
-   DTD subset) will be passed to the handler set with
-   XML_SetExternalEntityRefHandler.  The context passed will be 0.
-
-   Unlike external general entities, external parameter entities can
-   only be parsed synchronously.  If the external parameter entity is
-   to be parsed, it must be parsed during the call to the external
-   entity ref handler: the complete sequence of
-   XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and
-   XML_ParserFree calls must be made during this call.  After
-   XML_ExternalEntityParserCreate has been called to create the parser
-   for the external parameter entity (context must be 0 for this
-   call), it is illegal to make any calls on the old parser until
-   XML_ParserFree has been called on the newly created parser.
-   If the library has been compiled without support for parameter
-   entity parsing (ie without XML_DTD being defined), then
-   XML_SetParamEntityParsing will return 0 if parsing of parameter
-   entities is requested; otherwise it will return non-zero.
-   Note: If XML_SetParamEntityParsing is called after XML_Parse or
-      XML_ParseBuffer, then it has no effect and will always return 0.
-*/
-XMLPARSEAPI(int)
-XML_SetParamEntityParsing(XML_Parser parser,
-                          enum XML_ParamEntityParsing parsing);
-
-/* Sets the hash salt to use for internal hash calculations.
-   Helps in preventing DoS attacks based on predicting hash
-   function behavior. This must be called before parsing is started.
-   Returns 1 if successful, 0 when called after parsing has started.
-*/
-XMLPARSEAPI(int)
-XML_SetHashSalt(XML_Parser parser,
-                unsigned long hash_salt);
-
-/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
-   XML_GetErrorCode returns information about the error.
-*/
-XMLPARSEAPI(enum XML_Error)
-XML_GetErrorCode(XML_Parser parser);
-
-/* These functions return information about the current parse
-   location.  They may be called from any callback called to report
-   some parse event; in this case the location is the location of the
-   first of the sequence of characters that generated the event.  When
-   called from callbacks generated by declarations in the document
-   prologue, the location identified isn't as neatly defined, but will
-   be within the relevant markup.  When called outside of the callback
-   functions, the position indicated will be just past the last parse
-   event (regardless of whether there was an associated callback).
-   
-   They may also be called after returning from a call to XML_Parse
-   or XML_ParseBuffer.  If the return value is XML_STATUS_ERROR then
-   the location is the location of the character at which the error
-   was detected; otherwise the location is the location of the last
-   parse event, as described above.
-*/
-XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser);
-XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser);
-XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser);
-
-/* Return the number of bytes in the current event.
-   Returns 0 if the event is in an internal entity.
-*/
-XMLPARSEAPI(int)
-XML_GetCurrentByteCount(XML_Parser parser);
-
-/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets
-   the integer pointed to by offset to the offset within this buffer
-   of the current parse position, and sets the integer pointed to by size
-   to the size of this buffer (the number of input bytes). Otherwise
-   returns a NULL pointer. Also returns a NULL pointer if a parse isn't
-   active.
-
-   NOTE: The character pointer returned should not be used outside
-   the handler that makes the call.
-*/
-XMLPARSEAPI(const char *)
-XML_GetInputContext(XML_Parser parser,
-                    int *offset,
-                    int *size);
-
-/* For backwards compatibility with previous versions. */
-#define XML_GetErrorLineNumber   XML_GetCurrentLineNumber
-#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
-#define XML_GetErrorByteIndex    XML_GetCurrentByteIndex
-
-/* Frees the content model passed to the element declaration handler */
-XMLPARSEAPI(void)
-XML_FreeContentModel(XML_Parser parser, XML_Content *model);
-
-/* Exposing the memory handling functions used in Expat */
-XMLPARSEAPI(void *)
-XML_ATTR_MALLOC
-XML_ATTR_ALLOC_SIZE(2)
-XML_MemMalloc(XML_Parser parser, size_t size);
-
-XMLPARSEAPI(void *)
-XML_ATTR_ALLOC_SIZE(3)
-XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
-
-XMLPARSEAPI(void)
-XML_MemFree(XML_Parser parser, void *ptr);
-
-/* Frees memory used by the parser. */
-XMLPARSEAPI(void)
-XML_ParserFree(XML_Parser parser);
-
-/* Returns a string describing the error. */
-XMLPARSEAPI(const XML_LChar *)
-XML_ErrorString(enum XML_Error code);
-
-/* Return a string containing the version number of this expat */
-XMLPARSEAPI(const XML_LChar *)
-XML_ExpatVersion(void);
-
-typedef struct {
-  int major;
-  int minor;
-  int micro;
-} XML_Expat_Version;
-
-/* Return an XML_Expat_Version structure containing numeric version
-   number information for this version of expat.
-*/
-XMLPARSEAPI(XML_Expat_Version)
-XML_ExpatVersionInfo(void);
-
-/* Added in Expat 1.95.5. */
-enum XML_FeatureEnum {
-  XML_FEATURE_END = 0,
-  XML_FEATURE_UNICODE,
-  XML_FEATURE_UNICODE_WCHAR_T,
-  XML_FEATURE_DTD,
-  XML_FEATURE_CONTEXT_BYTES,
-  XML_FEATURE_MIN_SIZE,
-  XML_FEATURE_SIZEOF_XML_CHAR,
-  XML_FEATURE_SIZEOF_XML_LCHAR,
-  XML_FEATURE_NS,
-  XML_FEATURE_LARGE_SIZE,
-  XML_FEATURE_ATTR_INFO
-  /* Additional features must be added to the end of this enum. */
-};
-
-typedef struct {
-  enum XML_FeatureEnum  feature;
-  const XML_LChar       *name;
-  long int              value;
-} XML_Feature;
-
-XMLPARSEAPI(const XML_Feature *)
-XML_GetFeatureList(void);
-
-
-/* Expat follows the semantic versioning convention.
-   See http://semver.org.
-*/
-#define XML_MAJOR_VERSION 2
-#define XML_MINOR_VERSION 2
-#define XML_MICRO_VERSION 0
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* not Expat_INCLUDED */
diff --git a/components/expat/include/expat/expat_external.h b/components/expat/include/expat/expat_external.h
deleted file mode 100644 (file)
index aa08a2f..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-#ifndef Expat_External_INCLUDED
-#define Expat_External_INCLUDED 1
-
-/* External API definitions */
-
-#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
-#define XML_USE_MSC_EXTENSIONS 1
-#endif
-
-/* Expat tries very hard to make the API boundary very specifically
-   defined.  There are two macros defined to control this boundary;
-   each of these can be defined before including this header to
-   achieve some different behavior, but doing so it not recommended or
-   tested frequently.
-
-   XMLCALL    - The calling convention to use for all calls across the
-                "library boundary."  This will default to cdecl, and
-                try really hard to tell the compiler that's what we
-                want.
-
-   XMLIMPORT  - Whatever magic is needed to note that a function is
-                to be imported from a dynamically loaded library
-                (.dll, .so, or .sl, depending on your platform).
-
-   The XMLCALL macro was added in Expat 1.95.7.  The only one which is
-   expected to be directly useful in client code is XMLCALL.
-
-   Note that on at least some Unix versions, the Expat library must be
-   compiled with the cdecl calling convention as the default since
-   system headers may assume the cdecl convention.
-*/
-#ifndef XMLCALL
-#if defined(_MSC_VER)
-#define XMLCALL __cdecl
-#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
-#define XMLCALL __attribute__((cdecl))
-#else
-/* For any platform which uses this definition and supports more than
-   one calling convention, we need to extend this definition to
-   declare the convention used on that platform, if it's possible to
-   do so.
-
-   If this is the case for your platform, please file a bug report
-   with information on how to identify your platform via the C
-   pre-processor and how to specify the same calling convention as the
-   platform's malloc() implementation.
-*/
-#define XMLCALL
-#endif
-#endif  /* not defined XMLCALL */
-
-
-#if !defined(XML_STATIC) && !defined(XMLIMPORT)
-#ifndef XML_BUILDING_EXPAT
-/* using Expat from an application */
-
-#ifdef XML_USE_MSC_EXTENSIONS
-#define XMLIMPORT __declspec(dllimport)
-#endif
-
-#endif
-#endif  /* not defined XML_STATIC */
-
-#if !defined(XMLIMPORT) && defined(__GNUC__) && (__GNUC__ >= 4)
-#define XMLIMPORT __attribute__ ((visibility ("default")))
-#endif
-
-/* If we didn't define it above, define it away: */
-#ifndef XMLIMPORT
-#define XMLIMPORT
-#endif
-
-#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
-#define XML_ATTR_MALLOC __attribute__((__malloc__))
-#else
-#define XML_ATTR_MALLOC
-#endif
-
-#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
-#define XML_ATTR_ALLOC_SIZE(x)  __attribute__((__alloc_size__(x)))
-#else
-#define XML_ATTR_ALLOC_SIZE(x)
-#endif
-
-#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef XML_UNICODE_WCHAR_T
-#define XML_UNICODE
-#endif
-
-#ifdef XML_UNICODE     /* Information is UTF-16 encoded. */
-#ifdef XML_UNICODE_WCHAR_T
-typedef wchar_t XML_Char;
-typedef wchar_t XML_LChar;
-#else
-typedef unsigned short XML_Char;
-typedef char XML_LChar;
-#endif /* XML_UNICODE_WCHAR_T */
-#else                  /* Information is UTF-8 encoded. */
-typedef char XML_Char;
-typedef char XML_LChar;
-#endif /* XML_UNICODE */
-
-#ifdef XML_LARGE_SIZE  /* Use large integers for file/stream positions. */
-#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
-typedef __int64 XML_Index; 
-typedef unsigned __int64 XML_Size;
-#else
-typedef long long XML_Index;
-typedef unsigned long long XML_Size;
-#endif
-#else
-typedef long XML_Index;
-typedef unsigned long XML_Size;
-#endif /* XML_LARGE_SIZE */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* not Expat_External_INCLUDED */
diff --git a/components/expat/include/expat/iasciitab.h b/components/expat/include/expat/iasciitab.h
deleted file mode 100644 (file)
index 24a1d5c..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
-/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
-/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
-/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
-/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
-/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
-/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
-/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
-/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
-/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
-/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
-/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/components/expat/include/expat/internal.h b/components/expat/include/expat/internal.h
deleted file mode 100644 (file)
index 94cb98e..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* internal.h
-
-   Internal definitions used by Expat.  This is not needed to compile
-   client code.
-
-   The following calling convention macros are defined for frequently
-   called functions:
-
-   FASTCALL    - Used for those internal functions that have a simple
-                 body and a low number of arguments and local variables.
-
-   PTRCALL     - Used for functions called though function pointers.
-
-   PTRFASTCALL - Like PTRCALL, but for low number of arguments.
-
-   inline      - Used for selected internal functions for which inlining
-                 may improve performance on some platforms.
-
-   Note: Use of these macros is based on judgement, not hard rules,
-         and therefore subject to change.
-*/
-
-#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__)
-/* We'll use this version by default only where we know it helps.
-
-   regparm() generates warnings on Solaris boxes.   See SF bug #692878.
-
-   Instability reported with egcs on a RedHat Linux 7.3.
-   Let's comment out:
-   #define FASTCALL __attribute__((stdcall, regparm(3)))
-   and let's try this:
-*/
-#define FASTCALL __attribute__((regparm(3)))
-#define PTRFASTCALL __attribute__((regparm(3)))
-#endif
-
-/* Using __fastcall seems to have an unexpected negative effect under
-   MS VC++, especially for function pointers, so we won't use it for
-   now on that platform. It may be reconsidered for a future release
-   if it can be made more effective.
-   Likely reason: __fastcall on Windows is like stdcall, therefore
-   the compiler cannot perform stack optimizations for call clusters.
-*/
-
-/* Make sure all of these are defined if they aren't already. */
-
-#ifndef FASTCALL
-#define FASTCALL
-#endif
-
-#ifndef PTRCALL
-#define PTRCALL
-#endif
-
-#ifndef PTRFASTCALL
-#define PTRFASTCALL
-#endif
-
-#ifndef XML_MIN_SIZE
-#if !defined(__cplusplus) && !defined(inline)
-#ifdef __GNUC__
-#define inline __inline
-#endif /* __GNUC__ */
-#endif
-#endif /* XML_MIN_SIZE */
-
-#ifdef __cplusplus
-#define inline inline
-#else
-#ifndef inline
-#define inline
-#endif
-#endif
-
-#ifndef UNUSED_P
-# ifdef __GNUC__
-#  define UNUSED_P(p) UNUSED_ ## p __attribute__((__unused__))
-# else
-#  define UNUSED_P(p) UNUSED_ ## p
-# endif
-#endif
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-void
-align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef);
-
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/components/expat/include/expat/latin1tab.h b/components/expat/include/expat/latin1tab.h
deleted file mode 100644 (file)
index 53c25d7..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
-/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
-/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
-/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
diff --git a/components/expat/include/expat/nametab.h b/components/expat/include/expat/nametab.h
deleted file mode 100644 (file)
index b05e62c..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-static const unsigned namingBitmap[] = {
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE,
-0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF,
-0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF,
-0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
-0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
-0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
-0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
-0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
-0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF,
-0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000,
-0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060,
-0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003,
-0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003,
-0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
-0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001,
-0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003,
-0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000,
-0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003,
-0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003,
-0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000,
-0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000,
-0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF,
-0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB,
-0x40000000, 0xF580C900, 0x00000007, 0x02010800,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
-0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
-0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
-0x00000000, 0x00004C40, 0x00000000, 0x00000000,
-0x00000007, 0x00000000, 0x00000000, 0x00000000,
-0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF,
-0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF,
-0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
-0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE,
-0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF,
-0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
-0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000,
-0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003,
-0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
-0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
-0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
-0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
-0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
-0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF,
-0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF,
-0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF,
-0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF,
-0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0,
-0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1,
-0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3,
-0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80,
-0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
-0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3,
-0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000,
-0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000,
-0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF,
-0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x1FFF0000, 0x00000002,
-0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF,
-0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF,
-};
-static const unsigned char nmstrtPages[] = {
-0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00,
-0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
-0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-static const unsigned char namePages[] = {
-0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00,
-0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
-0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
-0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
diff --git a/components/expat/include/expat/utf8tab.h b/components/expat/include/expat/utf8tab.h
deleted file mode 100644 (file)
index 7bb3e77..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-
-/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
-/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,
diff --git a/components/expat/include/expat/xmlrole.h b/components/expat/include/expat/xmlrole.h
deleted file mode 100644 (file)
index 4dd9f06..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-#ifndef XmlRole_INCLUDED
-#define XmlRole_INCLUDED 1
-
-#ifdef __VMS
-/*      0        1         2         3      0        1         2         3
-        1234567890123456789012345678901     1234567890123456789012345678901 */
-#define XmlPrologStateInitExternalEntity    XmlPrologStateInitExternalEnt
-#endif
-
-#include "xmltok.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-enum {
-  XML_ROLE_ERROR = -1,
-  XML_ROLE_NONE = 0,
-  XML_ROLE_XML_DECL,
-  XML_ROLE_INSTANCE_START,
-  XML_ROLE_DOCTYPE_NONE,
-  XML_ROLE_DOCTYPE_NAME,
-  XML_ROLE_DOCTYPE_SYSTEM_ID,
-  XML_ROLE_DOCTYPE_PUBLIC_ID,
-  XML_ROLE_DOCTYPE_INTERNAL_SUBSET,
-  XML_ROLE_DOCTYPE_CLOSE,
-  XML_ROLE_GENERAL_ENTITY_NAME,
-  XML_ROLE_PARAM_ENTITY_NAME,
-  XML_ROLE_ENTITY_NONE,
-  XML_ROLE_ENTITY_VALUE,
-  XML_ROLE_ENTITY_SYSTEM_ID,
-  XML_ROLE_ENTITY_PUBLIC_ID,
-  XML_ROLE_ENTITY_COMPLETE,
-  XML_ROLE_ENTITY_NOTATION_NAME,
-  XML_ROLE_NOTATION_NONE,
-  XML_ROLE_NOTATION_NAME,
-  XML_ROLE_NOTATION_SYSTEM_ID,
-  XML_ROLE_NOTATION_NO_SYSTEM_ID,
-  XML_ROLE_NOTATION_PUBLIC_ID,
-  XML_ROLE_ATTRIBUTE_NAME,
-  XML_ROLE_ATTRIBUTE_TYPE_CDATA,
-  XML_ROLE_ATTRIBUTE_TYPE_ID,
-  XML_ROLE_ATTRIBUTE_TYPE_IDREF,
-  XML_ROLE_ATTRIBUTE_TYPE_IDREFS,
-  XML_ROLE_ATTRIBUTE_TYPE_ENTITY,
-  XML_ROLE_ATTRIBUTE_TYPE_ENTITIES,
-  XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN,
-  XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS,
-  XML_ROLE_ATTRIBUTE_ENUM_VALUE,
-  XML_ROLE_ATTRIBUTE_NOTATION_VALUE,
-  XML_ROLE_ATTLIST_NONE,
-  XML_ROLE_ATTLIST_ELEMENT_NAME,
-  XML_ROLE_IMPLIED_ATTRIBUTE_VALUE,
-  XML_ROLE_REQUIRED_ATTRIBUTE_VALUE,
-  XML_ROLE_DEFAULT_ATTRIBUTE_VALUE,
-  XML_ROLE_FIXED_ATTRIBUTE_VALUE,
-  XML_ROLE_ELEMENT_NONE,
-  XML_ROLE_ELEMENT_NAME,
-  XML_ROLE_CONTENT_ANY,
-  XML_ROLE_CONTENT_EMPTY,
-  XML_ROLE_CONTENT_PCDATA,
-  XML_ROLE_GROUP_OPEN,
-  XML_ROLE_GROUP_CLOSE,
-  XML_ROLE_GROUP_CLOSE_REP,
-  XML_ROLE_GROUP_CLOSE_OPT,
-  XML_ROLE_GROUP_CLOSE_PLUS,
-  XML_ROLE_GROUP_CHOICE,
-  XML_ROLE_GROUP_SEQUENCE,
-  XML_ROLE_CONTENT_ELEMENT,
-  XML_ROLE_CONTENT_ELEMENT_REP,
-  XML_ROLE_CONTENT_ELEMENT_OPT,
-  XML_ROLE_CONTENT_ELEMENT_PLUS,
-  XML_ROLE_PI,
-  XML_ROLE_COMMENT,
-#ifdef XML_DTD
-  XML_ROLE_TEXT_DECL,
-  XML_ROLE_IGNORE_SECT,
-  XML_ROLE_INNER_PARAM_ENTITY_REF,
-#endif /* XML_DTD */
-  XML_ROLE_PARAM_ENTITY_REF
-};
-
-typedef struct prolog_state {
-  int (PTRCALL *handler) (struct prolog_state *state,
-                          int tok,
-                          const char *ptr,
-                          const char *end,
-                          const ENCODING *enc);
-  unsigned level;
-  int role_none;
-#ifdef XML_DTD
-  unsigned includeLevel;
-  int documentEntity;
-  int inEntityValue;
-#endif /* XML_DTD */
-} PROLOG_STATE;
-
-void XmlPrologStateInit(PROLOG_STATE *);
-#ifdef XML_DTD
-void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
-#endif /* XML_DTD */
-
-#define XmlTokenRole(state, tok, ptr, end, enc) \
- (((state)->handler)(state, tok, ptr, end, enc))
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* not XmlRole_INCLUDED */
diff --git a/components/expat/include/expat/xmltok.h b/components/expat/include/expat/xmltok.h
deleted file mode 100644 (file)
index 752007e..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-#ifndef XmlTok_INCLUDED
-#define XmlTok_INCLUDED 1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* The following token may be returned by XmlContentTok */
-#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be
-                                    start of illegal ]]> sequence */
-/* The following tokens may be returned by both XmlPrologTok and
-   XmlContentTok.
-*/
-#define XML_TOK_NONE -4          /* The string to be scanned is empty */
-#define XML_TOK_TRAILING_CR -3   /* A CR at the end of the scan;
-                                    might be part of CRLF sequence */
-#define XML_TOK_PARTIAL_CHAR -2  /* only part of a multibyte sequence */
-#define XML_TOK_PARTIAL -1       /* only part of a token */
-#define XML_TOK_INVALID 0
-
-/* The following tokens are returned by XmlContentTok; some are also
-   returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok.
-*/
-#define XML_TOK_START_TAG_WITH_ATTS 1
-#define XML_TOK_START_TAG_NO_ATTS 2
-#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */
-#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4
-#define XML_TOK_END_TAG 5
-#define XML_TOK_DATA_CHARS 6
-#define XML_TOK_DATA_NEWLINE 7
-#define XML_TOK_CDATA_SECT_OPEN 8
-#define XML_TOK_ENTITY_REF 9
-#define XML_TOK_CHAR_REF 10               /* numeric character reference */
-
-/* The following tokens may be returned by both XmlPrologTok and
-   XmlContentTok.
-*/
-#define XML_TOK_PI 11                     /* processing instruction */
-#define XML_TOK_XML_DECL 12               /* XML decl or text decl */
-#define XML_TOK_COMMENT 13
-#define XML_TOK_BOM 14                    /* Byte order mark */
-
-/* The following tokens are returned only by XmlPrologTok */
-#define XML_TOK_PROLOG_S 15
-#define XML_TOK_DECL_OPEN 16              /* <!foo */
-#define XML_TOK_DECL_CLOSE 17             /* > */
-#define XML_TOK_NAME 18
-#define XML_TOK_NMTOKEN 19
-#define XML_TOK_POUND_NAME 20             /* #name */
-#define XML_TOK_OR 21                     /* | */
-#define XML_TOK_PERCENT 22
-#define XML_TOK_OPEN_PAREN 23
-#define XML_TOK_CLOSE_PAREN 24
-#define XML_TOK_OPEN_BRACKET 25
-#define XML_TOK_CLOSE_BRACKET 26
-#define XML_TOK_LITERAL 27
-#define XML_TOK_PARAM_ENTITY_REF 28
-#define XML_TOK_INSTANCE_START 29
-
-/* The following occur only in element type declarations */
-#define XML_TOK_NAME_QUESTION 30          /* name? */
-#define XML_TOK_NAME_ASTERISK 31          /* name* */
-#define XML_TOK_NAME_PLUS 32              /* name+ */
-#define XML_TOK_COND_SECT_OPEN 33         /* <![ */
-#define XML_TOK_COND_SECT_CLOSE 34        /* ]]> */
-#define XML_TOK_CLOSE_PAREN_QUESTION 35   /* )? */
-#define XML_TOK_CLOSE_PAREN_ASTERISK 36   /* )* */
-#define XML_TOK_CLOSE_PAREN_PLUS 37       /* )+ */
-#define XML_TOK_COMMA 38
-
-/* The following token is returned only by XmlAttributeValueTok */
-#define XML_TOK_ATTRIBUTE_VALUE_S 39
-
-/* The following token is returned only by XmlCdataSectionTok */
-#define XML_TOK_CDATA_SECT_CLOSE 40
-
-/* With namespace processing this is returned by XmlPrologTok for a
-   name with a colon.
-*/
-#define XML_TOK_PREFIXED_NAME 41
-
-#ifdef XML_DTD
-#define XML_TOK_IGNORE_SECT 42
-#endif /* XML_DTD */
-
-#ifdef XML_DTD
-#define XML_N_STATES 4
-#else /* not XML_DTD */
-#define XML_N_STATES 3
-#endif /* not XML_DTD */
-
-#define XML_PROLOG_STATE 0
-#define XML_CONTENT_STATE 1
-#define XML_CDATA_SECTION_STATE 2
-#ifdef XML_DTD
-#define XML_IGNORE_SECTION_STATE 3
-#endif /* XML_DTD */
-
-#define XML_N_LITERAL_TYPES 2
-#define XML_ATTRIBUTE_VALUE_LITERAL 0
-#define XML_ENTITY_VALUE_LITERAL 1
-
-/* The size of the buffer passed to XmlUtf8Encode must be at least this. */
-#define XML_UTF8_ENCODE_MAX 4
-/* The size of the buffer passed to XmlUtf16Encode must be at least this. */
-#define XML_UTF16_ENCODE_MAX 2
-
-typedef struct position {
-  /* first line and first column are 0 not 1 */
-  XML_Size lineNumber;
-  XML_Size columnNumber;
-} POSITION;
-
-typedef struct {
-  const char *name;
-  const char *valuePtr;
-  const char *valueEnd;
-  char normalized;
-} ATTRIBUTE;
-
-struct encoding;
-typedef struct encoding ENCODING;
-
-typedef int (PTRCALL *SCANNER)(const ENCODING *,
-                               const char *,
-                               const char *,
-                               const char **);
-
-enum XML_Convert_Result {
-  XML_CONVERT_COMPLETED = 0,
-  XML_CONVERT_INPUT_INCOMPLETE = 1,
-  XML_CONVERT_OUTPUT_EXHAUSTED = 2  /* and therefore potentially input remaining as well */
-};
-
-struct encoding {
-  SCANNER scanners[XML_N_STATES];
-  SCANNER literalScanners[XML_N_LITERAL_TYPES];
-  int (PTRCALL *sameName)(const ENCODING *,
-                          const char *,
-                          const char *);
-  int (PTRCALL *nameMatchesAscii)(const ENCODING *,
-                                  const char *,
-                                  const char *,
-                                  const char *);
-  int (PTRFASTCALL *nameLength)(const ENCODING *, const char *);
-  const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *);
-  int (PTRCALL *getAtts)(const ENCODING *enc,
-                         const char *ptr,
-                         int attsMax,
-                         ATTRIBUTE *atts);
-  int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
-  int (PTRCALL *predefinedEntityName)(const ENCODING *,
-                                      const char *,
-                                      const char *);
-  void (PTRCALL *updatePosition)(const ENCODING *,
-                                 const char *ptr,
-                                 const char *end,
-                                 POSITION *);
-  int (PTRCALL *isPublicId)(const ENCODING *enc,
-                            const char *ptr,
-                            const char *end,
-                            const char **badPtr);
-  enum XML_Convert_Result (PTRCALL *utf8Convert)(const ENCODING *enc,
-                              const char **fromP,
-                              const char *fromLim,
-                              char **toP,
-                              const char *toLim);
-  enum XML_Convert_Result (PTRCALL *utf16Convert)(const ENCODING *enc,
-                               const char **fromP,
-                               const char *fromLim,
-                               unsigned short **toP,
-                               const unsigned short *toLim);
-  int minBytesPerChar;
-  char isUtf8;
-  char isUtf16;
-};
-
-/* Scan the string starting at ptr until the end of the next complete
-   token, but do not scan past eptr.  Return an integer giving the
-   type of token.
-
-   Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set.
-
-   Return XML_TOK_PARTIAL when the string does not contain a complete
-   token; nextTokPtr will not be set.
-
-   Return XML_TOK_INVALID when the string does not start a valid
-   token; nextTokPtr will be set to point to the character which made
-   the token invalid.
-
-   Otherwise the string starts with a valid token; nextTokPtr will be
-   set to point to the character following the end of that token.
-
-   Each data character counts as a single token, but adjacent data
-   characters may be returned together.  Similarly for characters in
-   the prolog outside literals, comments and processing instructions.
-*/
-
-
-#define XmlTok(enc, state, ptr, end, nextTokPtr) \
-  (((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
-
-#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
-   XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
-
-#define XmlContentTok(enc, ptr, end, nextTokPtr) \
-   XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
-
-#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
-   XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
-
-#ifdef XML_DTD
-
-#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
-   XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
-
-#endif /* XML_DTD */
-
-/* This is used for performing a 2nd-level tokenization on the content
-   of a literal that has already been returned by XmlTok.
-*/
-#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
-  (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
-
-#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
-   XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
-
-#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
-   XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
-
-#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
-
-#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
-  (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
-
-#define XmlNameLength(enc, ptr) \
-  (((enc)->nameLength)(enc, ptr))
-
-#define XmlSkipS(enc, ptr) \
-  (((enc)->skipS)(enc, ptr))
-
-#define XmlGetAttributes(enc, ptr, attsMax, atts) \
-  (((enc)->getAtts)(enc, ptr, attsMax, atts))
-
-#define XmlCharRefNumber(enc, ptr) \
-  (((enc)->charRefNumber)(enc, ptr))
-
-#define XmlPredefinedEntityName(enc, ptr, end) \
-  (((enc)->predefinedEntityName)(enc, ptr, end))
-
-#define XmlUpdatePosition(enc, ptr, end, pos) \
-  (((enc)->updatePosition)(enc, ptr, end, pos))
-
-#define XmlIsPublicId(enc, ptr, end, badPtr) \
-  (((enc)->isPublicId)(enc, ptr, end, badPtr))
-
-#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
-  (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
-
-#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
-  (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
-
-typedef struct {
-  ENCODING initEnc;
-  const ENCODING **encPtr;
-} INIT_ENCODING;
-
-int XmlParseXmlDecl(int isGeneralTextEntity,
-                    const ENCODING *enc,
-                    const char *ptr,
-                    const char *end,
-                    const char **badPtr,
-                    const char **versionPtr,
-                    const char **versionEndPtr,
-                    const char **encodingNamePtr,
-                    const ENCODING **namedEncodingPtr,
-                    int *standalonePtr);
-
-int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
-const ENCODING *XmlGetUtf8InternalEncoding(void);
-const ENCODING *XmlGetUtf16InternalEncoding(void);
-int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
-int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf);
-int XmlSizeOfUnknownEncoding(void);
-
-
-typedef int (XMLCALL *CONVERTER) (void *userData, const char *p);
-
-ENCODING *
-XmlInitUnknownEncoding(void *mem,
-                       int *table,
-                       CONVERTER convert,
-                       void *userData);
-
-int XmlParseXmlDeclNS(int isGeneralTextEntity,
-                      const ENCODING *enc,
-                      const char *ptr,
-                      const char *end,
-                      const char **badPtr,
-                      const char **versionPtr,
-                      const char **versionEndPtr,
-                      const char **encodingNamePtr,
-                      const ENCODING **namedEncodingPtr,
-                      int *standalonePtr);
-
-int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
-const ENCODING *XmlGetUtf8InternalEncodingNS(void);
-const ENCODING *XmlGetUtf16InternalEncodingNS(void);
-ENCODING *
-XmlInitUnknownEncodingNS(void *mem,
-                         int *table,
-                         CONVERTER convert,
-                         void *userData);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* not XmlTok_INCLUDED */
diff --git a/components/expat/include/expat/xmltok_impl.h b/components/expat/include/expat/xmltok_impl.h
deleted file mode 100644 (file)
index da0ea60..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-enum {
-  BT_NONXML,
-  BT_MALFORM,
-  BT_LT,
-  BT_AMP,
-  BT_RSQB,
-  BT_LEAD2,
-  BT_LEAD3,
-  BT_LEAD4,
-  BT_TRAIL,
-  BT_CR,
-  BT_LF,
-  BT_GT,
-  BT_QUOT,
-  BT_APOS,
-  BT_EQUALS,
-  BT_QUEST,
-  BT_EXCL,
-  BT_SOL,
-  BT_SEMI,
-  BT_NUM,
-  BT_LSQB,
-  BT_S,
-  BT_NMSTRT,
-  BT_COLON,
-  BT_HEX,
-  BT_DIGIT,
-  BT_NAME,
-  BT_MINUS,
-  BT_OTHER, /* known not to be a name or name start character */
-  BT_NONASCII, /* might be a name or name start character */
-  BT_PERCNT,
-  BT_LPAR,
-  BT_RPAR,
-  BT_AST,
-  BT_PLUS,
-  BT_COMMA,
-  BT_VERBAR
-};
-
-#include <stddef.h>
diff --git a/components/expat/library/xmlparse.c b/components/expat/library/xmlparse.c
deleted file mode 100644 (file)
index 0f9c7ae..0000000
+++ /dev/null
@@ -1,6477 +0,0 @@
-/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-#include <stddef.h>
-#include <string.h>                     /* memset(), memcpy() */
-#include <assert.h>
-#include <limits.h>                     /* UINT_MAX */
-
-#ifdef WIN32
-#define getpid GetCurrentProcessId
-#else
-#include <sys/time.h>                   /* gettimeofday() */
-#include <sys/types.h>                  /* getpid() */
-#include <unistd.h>                     /* getpid() */
-#endif
-
-#define XML_BUILDING_EXPAT 1
-
-#ifdef WIN32
-#include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
-#elif defined(HAVE_EXPAT_CONFIG_H)
-#include <expat_config.h>
-#endif /* ndef WIN32 */
-
-#include "ascii.h"
-#include "expat.h"
-
-#ifdef XML_UNICODE
-#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
-#define XmlConvert XmlUtf16Convert
-#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
-#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
-#define XmlEncode XmlUtf16Encode
-/* Using pointer subtraction to convert to integer type. */
-#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))
-typedef unsigned short ICHAR;
-#else
-#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
-#define XmlConvert XmlUtf8Convert
-#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
-#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
-#define XmlEncode XmlUtf8Encode
-#define MUST_CONVERT(enc, s) (!(enc)->isUtf8)
-typedef char ICHAR;
-#endif
-
-
-#ifndef XML_NS
-
-#define XmlInitEncodingNS XmlInitEncoding
-#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
-#undef XmlGetInternalEncodingNS
-#define XmlGetInternalEncodingNS XmlGetInternalEncoding
-#define XmlParseXmlDeclNS XmlParseXmlDecl
-
-#endif
-
-#ifdef XML_UNICODE
-
-#ifdef XML_UNICODE_WCHAR_T
-#define XML_T(x) (const wchar_t)x
-#define XML_L(x) L ## x
-#else
-#define XML_T(x) (const unsigned short)x
-#define XML_L(x) x
-#endif
-
-#else
-
-#define XML_T(x) x
-#define XML_L(x) x
-
-#endif
-
-/* Round up n to be a multiple of sz, where sz is a power of 2. */
-#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
-
-/* Handle the case where memmove() doesn't exist. */
-#ifndef HAVE_MEMMOVE
-#ifdef HAVE_BCOPY
-#define memmove(d,s,l) bcopy((s),(d),(l))
-#else
-//#error memmove does not exist on this platform, nor is a substitute available
-#endif /* HAVE_BCOPY */
-#endif /* HAVE_MEMMOVE */
-
-#include "internal.h"
-#include "xmltok.h"
-#include "xmlrole.h"
-
-typedef const XML_Char *KEY;
-
-typedef struct {
-  KEY name;
-} NAMED;
-
-typedef struct {
-  NAMED **v;
-  unsigned char power;
-  size_t size;
-  size_t used;
-  const XML_Memory_Handling_Suite *mem;
-} HASH_TABLE;
-
-/* Basic character hash algorithm, taken from Python's string hash:
-   h = h * 1000003 ^ character, the constant being a prime number.
-
-*/
-#ifdef XML_UNICODE
-#define CHAR_HASH(h, c) \
-  (((h) * 0xF4243) ^ (unsigned short)(c))
-#else
-#define CHAR_HASH(h, c) \
-  (((h) * 0xF4243) ^ (unsigned char)(c))
-#endif
-
-/* For probing (after a collision) we need a step size relative prime
-   to the hash table size, which is a power of 2. We use double-hashing,
-   since we can calculate a second hash value cheaply by taking those bits
-   of the first hash value that were discarded (masked out) when the table
-   index was calculated: index = hash & mask, where mask = table->size - 1.
-   We limit the maximum step size to table->size / 4 (mask >> 2) and make
-   it odd, since odd numbers are always relative prime to a power of 2.
-*/
-#define SECOND_HASH(hash, mask, power) \
-  ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
-#define PROBE_STEP(hash, mask, power) \
-  ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
-
-typedef struct {
-  NAMED **p;
-  NAMED **end;
-} HASH_TABLE_ITER;
-
-#define INIT_TAG_BUF_SIZE 32  /* must be a multiple of sizeof(XML_Char) */
-#define INIT_DATA_BUF_SIZE 1024
-#define INIT_ATTS_SIZE 16
-#define INIT_ATTS_VERSION 0xFFFFFFFF
-#define INIT_BLOCK_SIZE 1024
-#define INIT_BUFFER_SIZE 1024
-
-#define EXPAND_SPARE 24
-
-typedef struct binding {
-  struct prefix *prefix;
-  struct binding *nextTagBinding;
-  struct binding *prevPrefixBinding;
-  const struct attribute_id *attId;
-  XML_Char *uri;
-  int uriLen;
-  int uriAlloc;
-} BINDING;
-
-typedef struct prefix {
-  const XML_Char *name;
-  BINDING *binding;
-} PREFIX;
-
-typedef struct {
-  const XML_Char *str;
-  const XML_Char *localPart;
-  const XML_Char *prefix;
-  int strLen;
-  int uriLen;
-  int prefixLen;
-} TAG_NAME;
-
-/* TAG represents an open element.
-   The name of the element is stored in both the document and API
-   encodings.  The memory buffer 'buf' is a separately-allocated
-   memory area which stores the name.  During the XML_Parse()/
-   XMLParseBuffer() when the element is open, the memory for the 'raw'
-   version of the name (in the document encoding) is shared with the
-   document buffer.  If the element is open across calls to
-   XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to
-   contain the 'raw' name as well.
-
-   A parser re-uses these structures, maintaining a list of allocated
-   TAG objects in a free list.
-*/
-typedef struct tag {
-  struct tag *parent;           /* parent of this element */
-  const char *rawName;          /* tagName in the original encoding */
-  int rawNameLength;
-  TAG_NAME name;                /* tagName in the API encoding */
-  char *buf;                    /* buffer for name components */
-  char *bufEnd;                 /* end of the buffer */
-  BINDING *bindings;
-} TAG;
-
-typedef struct {
-  const XML_Char *name;
-  const XML_Char *textPtr;
-  int textLen;                  /* length in XML_Chars */
-  int processed;                /* # of processed bytes - when suspended */
-  const XML_Char *systemId;
-  const XML_Char *base;
-  const XML_Char *publicId;
-  const XML_Char *notation;
-  XML_Bool open;
-  XML_Bool is_param;
-  XML_Bool is_internal; /* true if declared in internal subset outside PE */
-} ENTITY;
-
-typedef struct {
-  enum XML_Content_Type         type;
-  enum XML_Content_Quant        quant;
-  const XML_Char *              name;
-  int                           firstchild;
-  int                           lastchild;
-  int                           childcnt;
-  int                           nextsib;
-} CONTENT_SCAFFOLD;
-
-#define INIT_SCAFFOLD_ELEMENTS 32
-
-typedef struct block {
-  struct block *next;
-  int size;
-  XML_Char s[1];
-} BLOCK;
-
-typedef struct {
-  BLOCK *blocks;
-  BLOCK *freeBlocks;
-  const XML_Char *end;
-  XML_Char *ptr;
-  XML_Char *start;
-  const XML_Memory_Handling_Suite *mem;
-} STRING_POOL;
-
-/* The XML_Char before the name is used to determine whether
-   an attribute has been specified. */
-typedef struct attribute_id {
-  XML_Char *name;
-  PREFIX *prefix;
-  XML_Bool maybeTokenized;
-  XML_Bool xmlns;
-} ATTRIBUTE_ID;
-
-typedef struct {
-  const ATTRIBUTE_ID *id;
-  XML_Bool isCdata;
-  const XML_Char *value;
-} DEFAULT_ATTRIBUTE;
-
-typedef struct {
-  unsigned long version;
-  unsigned long hash;
-  const XML_Char *uriName;
-} NS_ATT;
-
-typedef struct {
-  const XML_Char *name;
-  PREFIX *prefix;
-  const ATTRIBUTE_ID *idAtt;
-  int nDefaultAtts;
-  int allocDefaultAtts;
-  DEFAULT_ATTRIBUTE *defaultAtts;
-} ELEMENT_TYPE;
-
-typedef struct {
-  HASH_TABLE generalEntities;
-  HASH_TABLE elementTypes;
-  HASH_TABLE attributeIds;
-  HASH_TABLE prefixes;
-  STRING_POOL pool;
-  STRING_POOL entityValuePool;
-  /* false once a parameter entity reference has been skipped */
-  XML_Bool keepProcessing;
-  /* true once an internal or external PE reference has been encountered;
-     this includes the reference to an external subset */
-  XML_Bool hasParamEntityRefs;
-  XML_Bool standalone;
-#ifdef XML_DTD
-  /* indicates if external PE has been read */
-  XML_Bool paramEntityRead;
-  HASH_TABLE paramEntities;
-#endif /* XML_DTD */
-  PREFIX defaultPrefix;
-  /* === scaffolding for building content model === */
-  XML_Bool in_eldecl;
-  CONTENT_SCAFFOLD *scaffold;
-  unsigned contentStringLen;
-  unsigned scaffSize;
-  unsigned scaffCount;
-  int scaffLevel;
-  int *scaffIndex;
-} DTD;
-
-typedef struct open_internal_entity {
-  const char *internalEventPtr;
-  const char *internalEventEndPtr;
-  struct open_internal_entity *next;
-  ENTITY *entity;
-  int startTagLevel;
-  XML_Bool betweenDecl; /* WFC: PE Between Declarations */
-} OPEN_INTERNAL_ENTITY;
-
-typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
-                                         const char *start,
-                                         const char *end,
-                                         const char **endPtr);
-
-static Processor prologProcessor;
-static Processor prologInitProcessor;
-static Processor contentProcessor;
-static Processor cdataSectionProcessor;
-#ifdef XML_DTD
-static Processor ignoreSectionProcessor;
-static Processor externalParEntProcessor;
-static Processor externalParEntInitProcessor;
-static Processor entityValueProcessor;
-static Processor entityValueInitProcessor;
-#endif /* XML_DTD */
-static Processor epilogProcessor;
-static Processor errorProcessor;
-static Processor externalEntityInitProcessor;
-static Processor externalEntityInitProcessor2;
-static Processor externalEntityInitProcessor3;
-static Processor externalEntityContentProcessor;
-static Processor internalEntityProcessor;
-
-static enum XML_Error
-handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);
-static enum XML_Error
-processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
-               const char *s, const char *next);
-static enum XML_Error
-initializeEncoding(XML_Parser parser);
-static enum XML_Error
-doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
-         const char *end, int tok, const char *next, const char **nextPtr,
-         XML_Bool haveMore);
-static enum XML_Error
-processInternalEntity(XML_Parser parser, ENTITY *entity,
-                      XML_Bool betweenDecl);
-static enum XML_Error
-doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
-          const char *start, const char *end, const char **endPtr,
-          XML_Bool haveMore);
-static enum XML_Error
-doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
-               const char *end, const char **nextPtr, XML_Bool haveMore);
-#ifdef XML_DTD
-static enum XML_Error
-doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
-                const char *end, const char **nextPtr, XML_Bool haveMore);
-#endif /* XML_DTD */
-
-static enum XML_Error
-storeAtts(XML_Parser parser, const ENCODING *, const char *s,
-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
-static enum XML_Error
-addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
-           const XML_Char *uri, BINDING **bindingsPtr);
-static int
-defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
-                XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);
-static enum XML_Error
-storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
-                    const char *, const char *, STRING_POOL *);
-static enum XML_Error
-appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
-                     const char *, const char *, STRING_POOL *);
-static ATTRIBUTE_ID *
-getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
-               const char *end);
-static int
-setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
-static enum XML_Error
-storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
-                 const char *end);
-static int
-reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
-                            const char *start, const char *end);
-static int
-reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
-              const char *end);
-static void
-reportDefault(XML_Parser parser, const ENCODING *enc, const char *start,
-              const char *end);
-
-static const XML_Char * getContext(XML_Parser parser);
-static XML_Bool
-setContext(XML_Parser parser, const XML_Char *context);
-
-static void FASTCALL normalizePublicId(XML_Char *s);
-
-static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
-/* do not call if parentParser != NULL */
-static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
-static void
-dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
-static int
-dtdCopy(XML_Parser oldParser,
-        DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
-static int
-copyEntityTable(XML_Parser oldParser,
-                HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
-static NAMED *
-lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize);
-static void FASTCALL
-hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
-static void FASTCALL hashTableClear(HASH_TABLE *);
-static void FASTCALL hashTableDestroy(HASH_TABLE *);
-static void FASTCALL
-hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
-static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
-
-static void FASTCALL
-poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms);
-static void FASTCALL poolClear(STRING_POOL *);
-static void FASTCALL poolDestroy(STRING_POOL *);
-static XML_Char *
-poolAppend(STRING_POOL *pool, const ENCODING *enc,
-           const char *ptr, const char *end);
-static XML_Char *
-poolStoreString(STRING_POOL *pool, const ENCODING *enc,
-                const char *ptr, const char *end);
-static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
-static const XML_Char * FASTCALL
-poolCopyString(STRING_POOL *pool, const XML_Char *s);
-static const XML_Char *
-poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n);
-static const XML_Char * FASTCALL
-poolAppendString(STRING_POOL *pool, const XML_Char *s);
-
-static int FASTCALL nextScaffoldPart(XML_Parser parser);
-static XML_Content * build_model(XML_Parser parser);
-static ELEMENT_TYPE *
-getElementType(XML_Parser parser, const ENCODING *enc,
-               const char *ptr, const char *end);
-
-static unsigned long generate_hash_secret_salt(XML_Parser parser);
-static XML_Bool startParsing(XML_Parser parser);
-
-static XML_Parser
-parserCreate(const XML_Char *encodingName,
-             const XML_Memory_Handling_Suite *memsuite,
-             const XML_Char *nameSep,
-             DTD *dtd);
-
-static void
-parserInit(XML_Parser parser, const XML_Char *encodingName);
-
-#define poolStart(pool) ((pool)->start)
-#define poolEnd(pool) ((pool)->ptr)
-#define poolLength(pool) ((pool)->ptr - (pool)->start)
-#define poolChop(pool) ((void)--(pool->ptr))
-#define poolLastChar(pool) (((pool)->ptr)[-1])
-#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
-#define poolFinish(pool) ((pool)->start = (pool)->ptr)
-#define poolAppendChar(pool, c) \
-  (((pool)->ptr == (pool)->end && !poolGrow(pool)) \
-   ? 0 \
-   : ((*((pool)->ptr)++ = c), 1))
-
-struct XML_ParserStruct {
-  /* The first member must be userData so that the XML_GetUserData
-     macro works. */
-  void *m_userData;
-  void *m_handlerArg;
-  char *m_buffer;
-  const XML_Memory_Handling_Suite m_mem;
-  /* first character to be parsed */
-  const char *m_bufferPtr;
-  /* past last character to be parsed */
-  char *m_bufferEnd;
-  /* allocated end of buffer */
-  const char *m_bufferLim;
-  XML_Index m_parseEndByteIndex;
-  const char *m_parseEndPtr;
-  XML_Char *m_dataBuf;
-  XML_Char *m_dataBufEnd;
-  XML_StartElementHandler m_startElementHandler;
-  XML_EndElementHandler m_endElementHandler;
-  XML_CharacterDataHandler m_characterDataHandler;
-  XML_ProcessingInstructionHandler m_processingInstructionHandler;
-  XML_CommentHandler m_commentHandler;
-  XML_StartCdataSectionHandler m_startCdataSectionHandler;
-  XML_EndCdataSectionHandler m_endCdataSectionHandler;
-  XML_DefaultHandler m_defaultHandler;
-  XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler;
-  XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler;
-  XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler;
-  XML_NotationDeclHandler m_notationDeclHandler;
-  XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler;
-  XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler;
-  XML_NotStandaloneHandler m_notStandaloneHandler;
-  XML_ExternalEntityRefHandler m_externalEntityRefHandler;
-  XML_Parser m_externalEntityRefHandlerArg;
-  XML_SkippedEntityHandler m_skippedEntityHandler;
-  XML_UnknownEncodingHandler m_unknownEncodingHandler;
-  XML_ElementDeclHandler m_elementDeclHandler;
-  XML_AttlistDeclHandler m_attlistDeclHandler;
-  XML_EntityDeclHandler m_entityDeclHandler;
-  XML_XmlDeclHandler m_xmlDeclHandler;
-  const ENCODING *m_encoding;
-  INIT_ENCODING m_initEncoding;
-  const ENCODING *m_internalEncoding;
-  const XML_Char *m_protocolEncodingName;
-  XML_Bool m_ns;
-  XML_Bool m_ns_triplets;
-  void *m_unknownEncodingMem;
-  void *m_unknownEncodingData;
-  void *m_unknownEncodingHandlerData;
-  void (XMLCALL *m_unknownEncodingRelease)(void *);
-  PROLOG_STATE m_prologState;
-  Processor *m_processor;
-  enum XML_Error m_errorCode;
-  const char *m_eventPtr;
-  const char *m_eventEndPtr;
-  const char *m_positionPtr;
-  OPEN_INTERNAL_ENTITY *m_openInternalEntities;
-  OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
-  XML_Bool m_defaultExpandInternalEntities;
-  int m_tagLevel;
-  ENTITY *m_declEntity;
-  const XML_Char *m_doctypeName;
-  const XML_Char *m_doctypeSysid;
-  const XML_Char *m_doctypePubid;
-  const XML_Char *m_declAttributeType;
-  const XML_Char *m_declNotationName;
-  const XML_Char *m_declNotationPublicId;
-  ELEMENT_TYPE *m_declElementType;
-  ATTRIBUTE_ID *m_declAttributeId;
-  XML_Bool m_declAttributeIsCdata;
-  XML_Bool m_declAttributeIsId;
-  DTD *m_dtd;
-  const XML_Char *m_curBase;
-  TAG *m_tagStack;
-  TAG *m_freeTagList;
-  BINDING *m_inheritedBindings;
-  BINDING *m_freeBindingList;
-  int m_attsSize;
-  int m_nSpecifiedAtts;
-  int m_idAttIndex;
-  ATTRIBUTE *m_atts;
-  NS_ATT *m_nsAtts;
-  unsigned long m_nsAttsVersion;
-  unsigned char m_nsAttsPower;
-#ifdef XML_ATTR_INFO
-  XML_AttrInfo *m_attInfo;
-#endif
-  POSITION m_position;
-  STRING_POOL m_tempPool;
-  STRING_POOL m_temp2Pool;
-  char *m_groupConnector;
-  unsigned int m_groupSize;
-  XML_Char m_namespaceSeparator;
-  XML_Parser m_parentParser;
-  XML_ParsingStatus m_parsingStatus;
-#ifdef XML_DTD
-  XML_Bool m_isParamEntity;
-  XML_Bool m_useForeignDTD;
-  enum XML_ParamEntityParsing m_paramEntityParsing;
-#endif
-  unsigned long m_hash_secret_salt;
-};
-
-#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
-#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s)))
-#define FREE(p) (parser->m_mem.free_fcn((p)))
-
-#define userData (parser->m_userData)
-#define handlerArg (parser->m_handlerArg)
-#define startElementHandler (parser->m_startElementHandler)
-#define endElementHandler (parser->m_endElementHandler)
-#define characterDataHandler (parser->m_characterDataHandler)
-#define processingInstructionHandler \
-        (parser->m_processingInstructionHandler)
-#define commentHandler (parser->m_commentHandler)
-#define startCdataSectionHandler \
-        (parser->m_startCdataSectionHandler)
-#define endCdataSectionHandler (parser->m_endCdataSectionHandler)
-#define defaultHandler (parser->m_defaultHandler)
-#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler)
-#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler)
-#define unparsedEntityDeclHandler \
-        (parser->m_unparsedEntityDeclHandler)
-#define notationDeclHandler (parser->m_notationDeclHandler)
-#define startNamespaceDeclHandler \
-        (parser->m_startNamespaceDeclHandler)
-#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler)
-#define notStandaloneHandler (parser->m_notStandaloneHandler)
-#define externalEntityRefHandler \
-        (parser->m_externalEntityRefHandler)
-#define externalEntityRefHandlerArg \
-        (parser->m_externalEntityRefHandlerArg)
-#define internalEntityRefHandler \
-        (parser->m_internalEntityRefHandler)
-#define skippedEntityHandler (parser->m_skippedEntityHandler)
-#define unknownEncodingHandler (parser->m_unknownEncodingHandler)
-#define elementDeclHandler (parser->m_elementDeclHandler)
-#define attlistDeclHandler (parser->m_attlistDeclHandler)
-#define entityDeclHandler (parser->m_entityDeclHandler)
-#define xmlDeclHandler (parser->m_xmlDeclHandler)
-#define encoding (parser->m_encoding)
-#define initEncoding (parser->m_initEncoding)
-#define internalEncoding (parser->m_internalEncoding)
-#define unknownEncodingMem (parser->m_unknownEncodingMem)
-#define unknownEncodingData (parser->m_unknownEncodingData)
-#define unknownEncodingHandlerData \
-  (parser->m_unknownEncodingHandlerData)
-#define unknownEncodingRelease (parser->m_unknownEncodingRelease)
-#define protocolEncodingName (parser->m_protocolEncodingName)
-#define ns (parser->m_ns)
-#define ns_triplets (parser->m_ns_triplets)
-#define prologState (parser->m_prologState)
-#define processor (parser->m_processor)
-#define errorCode (parser->m_errorCode)
-#define eventPtr (parser->m_eventPtr)
-#define eventEndPtr (parser->m_eventEndPtr)
-#define positionPtr (parser->m_positionPtr)
-#define position (parser->m_position)
-#define openInternalEntities (parser->m_openInternalEntities)
-#define freeInternalEntities (parser->m_freeInternalEntities)
-#define defaultExpandInternalEntities \
-        (parser->m_defaultExpandInternalEntities)
-#define tagLevel (parser->m_tagLevel)
-#define buffer (parser->m_buffer)
-#define bufferPtr (parser->m_bufferPtr)
-#define bufferEnd (parser->m_bufferEnd)
-#define parseEndByteIndex (parser->m_parseEndByteIndex)
-#define parseEndPtr (parser->m_parseEndPtr)
-#define bufferLim (parser->m_bufferLim)
-#define dataBuf (parser->m_dataBuf)
-#define dataBufEnd (parser->m_dataBufEnd)
-#define _dtd (parser->m_dtd)
-#define curBase (parser->m_curBase)
-#define declEntity (parser->m_declEntity)
-#define doctypeName (parser->m_doctypeName)
-#define doctypeSysid (parser->m_doctypeSysid)
-#define doctypePubid (parser->m_doctypePubid)
-#define declAttributeType (parser->m_declAttributeType)
-#define declNotationName (parser->m_declNotationName)
-#define declNotationPublicId (parser->m_declNotationPublicId)
-#define declElementType (parser->m_declElementType)
-#define declAttributeId (parser->m_declAttributeId)
-#define declAttributeIsCdata (parser->m_declAttributeIsCdata)
-#define declAttributeIsId (parser->m_declAttributeIsId)
-#define freeTagList (parser->m_freeTagList)
-#define freeBindingList (parser->m_freeBindingList)
-#define inheritedBindings (parser->m_inheritedBindings)
-#define tagStack (parser->m_tagStack)
-#define atts (parser->m_atts)
-#define attsSize (parser->m_attsSize)
-#define nSpecifiedAtts (parser->m_nSpecifiedAtts)
-#define idAttIndex (parser->m_idAttIndex)
-#define nsAtts (parser->m_nsAtts)
-#define nsAttsVersion (parser->m_nsAttsVersion)
-#define nsAttsPower (parser->m_nsAttsPower)
-#define attInfo (parser->m_attInfo)
-#define tempPool (parser->m_tempPool)
-#define temp2Pool (parser->m_temp2Pool)
-#define groupConnector (parser->m_groupConnector)
-#define groupSize (parser->m_groupSize)
-#define namespaceSeparator (parser->m_namespaceSeparator)
-#define parentParser (parser->m_parentParser)
-#define ps_parsing (parser->m_parsingStatus.parsing)
-#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer)
-#ifdef XML_DTD
-#define isParamEntity (parser->m_isParamEntity)
-#define useForeignDTD (parser->m_useForeignDTD)
-#define paramEntityParsing (parser->m_paramEntityParsing)
-#endif /* XML_DTD */
-#define hash_secret_salt (parser->m_hash_secret_salt)
-
-XML_Parser XMLCALL
-XML_ParserCreate(const XML_Char *encodingName)
-{
-  return XML_ParserCreate_MM(encodingName, NULL, NULL);
-}
-
-XML_Parser XMLCALL
-XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
-{
-  XML_Char tmp[2];
-  *tmp = nsSep;
-  return XML_ParserCreate_MM(encodingName, NULL, tmp);
-}
-
-static const XML_Char implicitContext[] = {
-  ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p,
-  ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
-  ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g,
-  ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9,
-  ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e,
-  ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0'
-};
-
-static unsigned long
-gather_time_entropy(void)
-{
-#ifdef WIN32
-  FILETIME ft;
-  GetSystemTimeAsFileTime(&ft); /* never fails */
-  return ft.dwHighDateTime ^ ft.dwLowDateTime;
-#else
-  struct timeval tv;
-  int gettimeofday_res;
-
-  gettimeofday_res = gettimeofday(&tv, NULL);
-  assert (gettimeofday_res == 0);
-
-  /* Microseconds time is <20 bits entropy */
-  return tv.tv_usec;
-#endif
-}
-
-static unsigned long
-generate_hash_secret_salt(XML_Parser parser)
-{
-#ifdef __CloudABI__
-  unsigned long entropy;
-  (void)parser;
-  (void)gather_time_entropy;
-  arc4random_buf(&entropy, sizeof(entropy));
-  return entropy;
-#else
-  /* Process ID is 0 bits entropy if attacker has local access
-   * XML_Parser address is few bits of entropy if attacker has local access */
-//  const unsigned long entropy =
-//      gather_time_entropy() ^ getpid() ^ (unsigned long)parser;
-  const unsigned long entropy = (unsigned long)parser;
-
-  /* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */
-  if (sizeof(unsigned long) == 4) {
-    return entropy * 2147483647;
-  } else {
-    return entropy * (unsigned long)2305843009213693951;
-  }
-#endif
-}
-
-static XML_Bool  /* only valid for root parser */
-startParsing(XML_Parser parser)
-{
-    /* hash functions must be initialized before setContext() is called */
-    if (hash_secret_salt == 0)
-      hash_secret_salt = generate_hash_secret_salt(parser);
-    if (ns) {
-      /* implicit context only set for root parser, since child
-         parsers (i.e. external entity parsers) will inherit it
-      */
-      return setContext(parser, implicitContext);
-    }
-    return XML_TRUE;
-}
-
-XML_Parser XMLCALL
-XML_ParserCreate_MM(const XML_Char *encodingName,
-                    const XML_Memory_Handling_Suite *memsuite,
-                    const XML_Char *nameSep)
-{
-  return parserCreate(encodingName, memsuite, nameSep, NULL);
-}
-
-static XML_Parser
-parserCreate(const XML_Char *encodingName,
-             const XML_Memory_Handling_Suite *memsuite,
-             const XML_Char *nameSep,
-             DTD *dtd)
-{
-  XML_Parser parser;
-
-  if (memsuite) {
-    XML_Memory_Handling_Suite *mtemp;
-    parser = (XML_Parser)
-      memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
-    if (parser != NULL) {
-      mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
-      mtemp->malloc_fcn = memsuite->malloc_fcn;
-      mtemp->realloc_fcn = memsuite->realloc_fcn;
-      mtemp->free_fcn = memsuite->free_fcn;
-    }
-  }
-  else {
-    XML_Memory_Handling_Suite *mtemp;
-    parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
-    if (parser != NULL) {
-      mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
-      mtemp->malloc_fcn = malloc;
-      mtemp->realloc_fcn = realloc;
-      mtemp->free_fcn = free;
-    }
-  }
-
-  if (!parser)
-    return parser;
-
-  buffer = NULL;
-  bufferLim = NULL;
-
-  attsSize = INIT_ATTS_SIZE;
-  atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE));
-  if (atts == NULL) {
-    FREE(parser);
-    return NULL;
-  }
-#ifdef XML_ATTR_INFO
-  attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo));
-  if (attInfo == NULL) {
-    FREE(atts);
-    FREE(parser);
-    return NULL;
-  }
-#endif
-  dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
-  if (dataBuf == NULL) {
-    FREE(atts);
-#ifdef XML_ATTR_INFO
-    FREE(attInfo);
-#endif
-    FREE(parser);
-    return NULL;
-  }
-  dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
-
-  if (dtd)
-    _dtd = dtd;
-  else {
-    _dtd = dtdCreate(&parser->m_mem);
-    if (_dtd == NULL) {
-      FREE(dataBuf);
-      FREE(atts);
-#ifdef XML_ATTR_INFO
-      FREE(attInfo);
-#endif
-      FREE(parser);
-      return NULL;
-    }
-  }
-
-  freeBindingList = NULL;
-  freeTagList = NULL;
-  freeInternalEntities = NULL;
-
-  groupSize = 0;
-  groupConnector = NULL;
-
-  unknownEncodingHandler = NULL;
-  unknownEncodingHandlerData = NULL;
-
-  namespaceSeparator = ASCII_EXCL;
-  ns = XML_FALSE;
-  ns_triplets = XML_FALSE;
-
-  nsAtts = NULL;
-  nsAttsVersion = 0;
-  nsAttsPower = 0;
-
-  poolInit(&tempPool, &(parser->m_mem));
-  poolInit(&temp2Pool, &(parser->m_mem));
-  parserInit(parser, encodingName);
-
-  if (encodingName && !protocolEncodingName) {
-    XML_ParserFree(parser);
-    return NULL;
-  }
-
-  if (nameSep) {
-    ns = XML_TRUE;
-    internalEncoding = XmlGetInternalEncodingNS();
-    namespaceSeparator = *nameSep;
-  }
-  else {
-    internalEncoding = XmlGetInternalEncoding();
-  }
-
-  return parser;
-}
-
-static void
-parserInit(XML_Parser parser, const XML_Char *encodingName)
-{
-  processor = prologInitProcessor;
-  XmlPrologStateInit(&prologState);
-  protocolEncodingName = (encodingName != NULL
-                          ? poolCopyString(&tempPool, encodingName)
-                          : NULL);
-  curBase = NULL;
-  XmlInitEncoding(&initEncoding, &encoding, 0);
-  userData = NULL;
-  handlerArg = NULL;
-  startElementHandler = NULL;
-  endElementHandler = NULL;
-  characterDataHandler = NULL;
-  processingInstructionHandler = NULL;
-  commentHandler = NULL;
-  startCdataSectionHandler = NULL;
-  endCdataSectionHandler = NULL;
-  defaultHandler = NULL;
-  startDoctypeDeclHandler = NULL;
-  endDoctypeDeclHandler = NULL;
-  unparsedEntityDeclHandler = NULL;
-  notationDeclHandler = NULL;
-  startNamespaceDeclHandler = NULL;
-  endNamespaceDeclHandler = NULL;
-  notStandaloneHandler = NULL;
-  externalEntityRefHandler = NULL;
-  externalEntityRefHandlerArg = parser;
-  skippedEntityHandler = NULL;
-  elementDeclHandler = NULL;
-  attlistDeclHandler = NULL;
-  entityDeclHandler = NULL;
-  xmlDeclHandler = NULL;
-  bufferPtr = buffer;
-  bufferEnd = buffer;
-  parseEndByteIndex = 0;
-  parseEndPtr = NULL;
-  declElementType = NULL;
-  declAttributeId = NULL;
-  declEntity = NULL;
-  doctypeName = NULL;
-  doctypeSysid = NULL;
-  doctypePubid = NULL;
-  declAttributeType = NULL;
-  declNotationName = NULL;
-  declNotationPublicId = NULL;
-  declAttributeIsCdata = XML_FALSE;
-  declAttributeIsId = XML_FALSE;
-  memset(&position, 0, sizeof(POSITION));
-  errorCode = XML_ERROR_NONE;
-  eventPtr = NULL;
-  eventEndPtr = NULL;
-  positionPtr = NULL;
-  openInternalEntities = NULL;
-  defaultExpandInternalEntities = XML_TRUE;
-  tagLevel = 0;
-  tagStack = NULL;
-  inheritedBindings = NULL;
-  nSpecifiedAtts = 0;
-  unknownEncodingMem = NULL;
-  unknownEncodingRelease = NULL;
-  unknownEncodingData = NULL;
-  parentParser = NULL;
-  ps_parsing = XML_INITIALIZED;
-#ifdef XML_DTD
-  isParamEntity = XML_FALSE;
-  useForeignDTD = XML_FALSE;
-  paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
-#endif
-  hash_secret_salt = 0;
-}
-
-/* moves list of bindings to freeBindingList */
-static void FASTCALL
-moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
-{
-  while (bindings) {
-    BINDING *b = bindings;
-    bindings = bindings->nextTagBinding;
-    b->nextTagBinding = freeBindingList;
-    freeBindingList = b;
-  }
-}
-
-XML_Bool XMLCALL
-XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
-{
-  TAG *tStk;
-  OPEN_INTERNAL_ENTITY *openEntityList;
-  if (parentParser)
-    return XML_FALSE;
-  /* move tagStack to freeTagList */
-  tStk = tagStack;
-  while (tStk) {
-    TAG *tag = tStk;
-    tStk = tStk->parent;
-    tag->parent = freeTagList;
-    moveToFreeBindingList(parser, tag->bindings);
-    tag->bindings = NULL;
-    freeTagList = tag;
-  }
-  /* move openInternalEntities to freeInternalEntities */
-  openEntityList = openInternalEntities;
-  while (openEntityList) {
-    OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
-    openEntityList = openEntity->next;
-    openEntity->next = freeInternalEntities;
-    freeInternalEntities = openEntity;
-  }
-  moveToFreeBindingList(parser, inheritedBindings);
-  FREE(unknownEncodingMem);
-  if (unknownEncodingRelease)
-    unknownEncodingRelease(unknownEncodingData);
-  poolClear(&tempPool);
-  poolClear(&temp2Pool);
-  parserInit(parser, encodingName);
-  dtdReset(_dtd, &parser->m_mem);
-  return XML_TRUE;
-}
-
-enum XML_Status XMLCALL
-XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
-{
-  /* Block after XML_Parse()/XML_ParseBuffer() has been called.
-     XXX There's no way for the caller to determine which of the
-     XXX possible error cases caused the XML_STATUS_ERROR return.
-  */
-  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
-    return XML_STATUS_ERROR;
-  if (encodingName == NULL)
-    protocolEncodingName = NULL;
-  else {
-    protocolEncodingName = poolCopyString(&tempPool, encodingName);
-    if (!protocolEncodingName)
-      return XML_STATUS_ERROR;
-  }
-  return XML_STATUS_OK;
-}
-
-XML_Parser XMLCALL
-XML_ExternalEntityParserCreate(XML_Parser oldParser,
-                               const XML_Char *context,
-                               const XML_Char *encodingName)
-{
-  XML_Parser parser = oldParser;
-  DTD *newDtd = NULL;
-  DTD *oldDtd = _dtd;
-  XML_StartElementHandler oldStartElementHandler = startElementHandler;
-  XML_EndElementHandler oldEndElementHandler = endElementHandler;
-  XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
-  XML_ProcessingInstructionHandler oldProcessingInstructionHandler
-      = processingInstructionHandler;
-  XML_CommentHandler oldCommentHandler = commentHandler;
-  XML_StartCdataSectionHandler oldStartCdataSectionHandler
-      = startCdataSectionHandler;
-  XML_EndCdataSectionHandler oldEndCdataSectionHandler
-      = endCdataSectionHandler;
-  XML_DefaultHandler oldDefaultHandler = defaultHandler;
-  XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler
-      = unparsedEntityDeclHandler;
-  XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler;
-  XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler
-      = startNamespaceDeclHandler;
-  XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler
-      = endNamespaceDeclHandler;
-  XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler;
-  XML_ExternalEntityRefHandler oldExternalEntityRefHandler
-      = externalEntityRefHandler;
-  XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler;
-  XML_UnknownEncodingHandler oldUnknownEncodingHandler
-      = unknownEncodingHandler;
-  XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler;
-  XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler;
-  XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler;
-  XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler;
-  ELEMENT_TYPE * oldDeclElementType = declElementType;
-
-  void *oldUserData = userData;
-  void *oldHandlerArg = handlerArg;
-  XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
-  XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
-#ifdef XML_DTD
-  enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing;
-  int oldInEntityValue = prologState.inEntityValue;
-#endif
-  XML_Bool oldns_triplets = ns_triplets;
-  /* Note that the new parser shares the same hash secret as the old
-     parser, so that dtdCopy and copyEntityTable can lookup values
-     from hash tables associated with either parser without us having
-     to worry which hash secrets each table has.
-  */
-  unsigned long oldhash_secret_salt = hash_secret_salt;
-
-#ifdef XML_DTD
-  if (!context)
-    newDtd = oldDtd;
-#endif /* XML_DTD */
-
-  /* Note that the magical uses of the pre-processor to make field
-     access look more like C++ require that `parser' be overwritten
-     here.  This makes this function more painful to follow than it
-     would be otherwise.
-  */
-  if (ns) {
-    XML_Char tmp[2];
-    *tmp = namespaceSeparator;
-    parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
-  }
-  else {
-    parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
-  }
-
-  if (!parser)
-    return NULL;
-
-  startElementHandler = oldStartElementHandler;
-  endElementHandler = oldEndElementHandler;
-  characterDataHandler = oldCharacterDataHandler;
-  processingInstructionHandler = oldProcessingInstructionHandler;
-  commentHandler = oldCommentHandler;
-  startCdataSectionHandler = oldStartCdataSectionHandler;
-  endCdataSectionHandler = oldEndCdataSectionHandler;
-  defaultHandler = oldDefaultHandler;
-  unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
-  notationDeclHandler = oldNotationDeclHandler;
-  startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
-  endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
-  notStandaloneHandler = oldNotStandaloneHandler;
-  externalEntityRefHandler = oldExternalEntityRefHandler;
-  skippedEntityHandler = oldSkippedEntityHandler;
-  unknownEncodingHandler = oldUnknownEncodingHandler;
-  elementDeclHandler = oldElementDeclHandler;
-  attlistDeclHandler = oldAttlistDeclHandler;
-  entityDeclHandler = oldEntityDeclHandler;
-  xmlDeclHandler = oldXmlDeclHandler;
-  declElementType = oldDeclElementType;
-  userData = oldUserData;
-  if (oldUserData == oldHandlerArg)
-    handlerArg = userData;
-  else
-    handlerArg = parser;
-  if (oldExternalEntityRefHandlerArg != oldParser)
-    externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
-  defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
-  ns_triplets = oldns_triplets;
-  hash_secret_salt = oldhash_secret_salt;
-  parentParser = oldParser;
-#ifdef XML_DTD
-  paramEntityParsing = oldParamEntityParsing;
-  prologState.inEntityValue = oldInEntityValue;
-  if (context) {
-#endif /* XML_DTD */
-    if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem)
-      || !setContext(parser, context)) {
-      XML_ParserFree(parser);
-      return NULL;
-    }
-    processor = externalEntityInitProcessor;
-#ifdef XML_DTD
-  }
-  else {
-    /* The DTD instance referenced by _dtd is shared between the document's
-       root parser and external PE parsers, therefore one does not need to
-       call setContext. In addition, one also *must* not call setContext,
-       because this would overwrite existing prefix->binding pointers in
-       _dtd with ones that get destroyed with the external PE parser.
-       This would leave those prefixes with dangling pointers.
-    */
-    isParamEntity = XML_TRUE;
-    XmlPrologStateInitExternalEntity(&prologState);
-    processor = externalParEntInitProcessor;
-  }
-#endif /* XML_DTD */
-  return parser;
-}
-
-static void FASTCALL
-destroyBindings(BINDING *bindings, XML_Parser parser)
-{
-  for (;;) {
-    BINDING *b = bindings;
-    if (!b)
-      break;
-    bindings = b->nextTagBinding;
-    FREE(b->uri);
-    FREE(b);
-  }
-}
-
-void XMLCALL
-XML_ParserFree(XML_Parser parser)
-{
-  TAG *tagList;
-  OPEN_INTERNAL_ENTITY *entityList;
-  if (parser == NULL)
-    return;
-  /* free tagStack and freeTagList */
-  tagList = tagStack;
-  for (;;) {
-    TAG *p;
-    if (tagList == NULL) {
-      if (freeTagList == NULL)
-        break;
-      tagList = freeTagList;
-      freeTagList = NULL;
-    }
-    p = tagList;
-    tagList = tagList->parent;
-    FREE(p->buf);
-    destroyBindings(p->bindings, parser);
-    FREE(p);
-  }
-  /* free openInternalEntities and freeInternalEntities */
-  entityList = openInternalEntities;
-  for (;;) {
-    OPEN_INTERNAL_ENTITY *openEntity;
-    if (entityList == NULL) {
-      if (freeInternalEntities == NULL)
-        break;
-      entityList = freeInternalEntities;
-      freeInternalEntities = NULL;
-    }
-    openEntity = entityList;
-    entityList = entityList->next;
-    FREE(openEntity);
-  }
-
-  destroyBindings(freeBindingList, parser);
-  destroyBindings(inheritedBindings, parser);
-  poolDestroy(&tempPool);
-  poolDestroy(&temp2Pool);
-#ifdef XML_DTD
-  /* external parameter entity parsers share the DTD structure
-     parser->m_dtd with the root parser, so we must not destroy it
-  */
-  if (!isParamEntity && _dtd)
-#else
-  if (_dtd)
-#endif /* XML_DTD */
-    dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem);
-  FREE((void *)atts);
-#ifdef XML_ATTR_INFO
-  FREE((void *)attInfo);
-#endif
-  FREE(groupConnector);
-  FREE(buffer);
-  FREE(dataBuf);
-  FREE(nsAtts);
-  FREE(unknownEncodingMem);
-  if (unknownEncodingRelease)
-    unknownEncodingRelease(unknownEncodingData);
-  FREE(parser);
-}
-
-void XMLCALL
-XML_UseParserAsHandlerArg(XML_Parser parser)
-{
-  handlerArg = parser;
-}
-
-enum XML_Error XMLCALL
-XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
-{
-#ifdef XML_DTD
-  /* block after XML_Parse()/XML_ParseBuffer() has been called */
-  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
-    return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
-  useForeignDTD = useDTD;
-  return XML_ERROR_NONE;
-#else
-  return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
-#endif
-}
-
-void XMLCALL
-XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
-{
-  /* block after XML_Parse()/XML_ParseBuffer() has been called */
-  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
-    return;
-  ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
-}
-
-void XMLCALL
-XML_SetUserData(XML_Parser parser, void *p)
-{
-  if (handlerArg == userData)
-    handlerArg = userData = p;
-  else
-    userData = p;
-}
-
-enum XML_Status XMLCALL
-XML_SetBase(XML_Parser parser, const XML_Char *p)
-{
-  if (p) {
-    p = poolCopyString(&_dtd->pool, p);
-    if (!p)
-      return XML_STATUS_ERROR;
-    curBase = p;
-  }
-  else
-    curBase = NULL;
-  return XML_STATUS_OK;
-}
-
-const XML_Char * XMLCALL
-XML_GetBase(XML_Parser parser)
-{
-  return curBase;
-}
-
-int XMLCALL
-XML_GetSpecifiedAttributeCount(XML_Parser parser)
-{
-  return nSpecifiedAtts;
-}
-
-int XMLCALL
-XML_GetIdAttributeIndex(XML_Parser parser)
-{
-  return idAttIndex;
-}
-
-#ifdef XML_ATTR_INFO
-const XML_AttrInfo * XMLCALL
-XML_GetAttributeInfo(XML_Parser parser)
-{
-  return attInfo;
-}
-#endif
-
-void XMLCALL
-XML_SetElementHandler(XML_Parser parser,
-                      XML_StartElementHandler start,
-                      XML_EndElementHandler end)
-{
-  startElementHandler = start;
-  endElementHandler = end;
-}
-
-void XMLCALL
-XML_SetStartElementHandler(XML_Parser parser,
-                           XML_StartElementHandler start) {
-  startElementHandler = start;
-}
-
-void XMLCALL
-XML_SetEndElementHandler(XML_Parser parser,
-                         XML_EndElementHandler end) {
-  endElementHandler = end;
-}
-
-void XMLCALL
-XML_SetCharacterDataHandler(XML_Parser parser,
-                            XML_CharacterDataHandler handler)
-{
-  characterDataHandler = handler;
-}
-
-void XMLCALL
-XML_SetProcessingInstructionHandler(XML_Parser parser,
-                                    XML_ProcessingInstructionHandler handler)
-{
-  processingInstructionHandler = handler;
-}
-
-void XMLCALL
-XML_SetCommentHandler(XML_Parser parser,
-                      XML_CommentHandler handler)
-{
-  commentHandler = handler;
-}
-
-void XMLCALL
-XML_SetCdataSectionHandler(XML_Parser parser,
-                           XML_StartCdataSectionHandler start,
-                           XML_EndCdataSectionHandler end)
-{
-  startCdataSectionHandler = start;
-  endCdataSectionHandler = end;
-}
-
-void XMLCALL
-XML_SetStartCdataSectionHandler(XML_Parser parser,
-                                XML_StartCdataSectionHandler start) {
-  startCdataSectionHandler = start;
-}
-
-void XMLCALL
-XML_SetEndCdataSectionHandler(XML_Parser parser,
-                              XML_EndCdataSectionHandler end) {
-  endCdataSectionHandler = end;
-}
-
-void XMLCALL
-XML_SetDefaultHandler(XML_Parser parser,
-                      XML_DefaultHandler handler)
-{
-  defaultHandler = handler;
-  defaultExpandInternalEntities = XML_FALSE;
-}
-
-void XMLCALL
-XML_SetDefaultHandlerExpand(XML_Parser parser,
-                            XML_DefaultHandler handler)
-{
-  defaultHandler = handler;
-  defaultExpandInternalEntities = XML_TRUE;
-}
-
-void XMLCALL
-XML_SetDoctypeDeclHandler(XML_Parser parser,
-                          XML_StartDoctypeDeclHandler start,
-                          XML_EndDoctypeDeclHandler end)
-{
-  startDoctypeDeclHandler = start;
-  endDoctypeDeclHandler = end;
-}
-
-void XMLCALL
-XML_SetStartDoctypeDeclHandler(XML_Parser parser,
-                               XML_StartDoctypeDeclHandler start) {
-  startDoctypeDeclHandler = start;
-}
-
-void XMLCALL
-XML_SetEndDoctypeDeclHandler(XML_Parser parser,
-                             XML_EndDoctypeDeclHandler end) {
-  endDoctypeDeclHandler = end;
-}
-
-void XMLCALL
-XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
-                                 XML_UnparsedEntityDeclHandler handler)
-{
-  unparsedEntityDeclHandler = handler;
-}
-
-void XMLCALL
-XML_SetNotationDeclHandler(XML_Parser parser,
-                           XML_NotationDeclHandler handler)
-{
-  notationDeclHandler = handler;
-}
-
-void XMLCALL
-XML_SetNamespaceDeclHandler(XML_Parser parser,
-                            XML_StartNamespaceDeclHandler start,
-                            XML_EndNamespaceDeclHandler end)
-{
-  startNamespaceDeclHandler = start;
-  endNamespaceDeclHandler = end;
-}
-
-void XMLCALL
-XML_SetStartNamespaceDeclHandler(XML_Parser parser,
-                                 XML_StartNamespaceDeclHandler start) {
-  startNamespaceDeclHandler = start;
-}
-
-void XMLCALL
-XML_SetEndNamespaceDeclHandler(XML_Parser parser,
-                               XML_EndNamespaceDeclHandler end) {
-  endNamespaceDeclHandler = end;
-}
-
-void XMLCALL
-XML_SetNotStandaloneHandler(XML_Parser parser,
-                            XML_NotStandaloneHandler handler)
-{
-  notStandaloneHandler = handler;
-}
-
-void XMLCALL
-XML_SetExternalEntityRefHandler(XML_Parser parser,
-                                XML_ExternalEntityRefHandler handler)
-{
-  externalEntityRefHandler = handler;
-}
-
-void XMLCALL
-XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
-{
-  if (arg)
-    externalEntityRefHandlerArg = (XML_Parser)arg;
-  else
-    externalEntityRefHandlerArg = parser;
-}
-
-void XMLCALL
-XML_SetSkippedEntityHandler(XML_Parser parser,
-                            XML_SkippedEntityHandler handler)
-{
-  skippedEntityHandler = handler;
-}
-
-void XMLCALL
-XML_SetUnknownEncodingHandler(XML_Parser parser,
-                              XML_UnknownEncodingHandler handler,
-                              void *data)
-{
-  unknownEncodingHandler = handler;
-  unknownEncodingHandlerData = data;
-}
-
-void XMLCALL
-XML_SetElementDeclHandler(XML_Parser parser,
-                          XML_ElementDeclHandler eldecl)
-{
-  elementDeclHandler = eldecl;
-}
-
-void XMLCALL
-XML_SetAttlistDeclHandler(XML_Parser parser,
-                          XML_AttlistDeclHandler attdecl)
-{
-  attlistDeclHandler = attdecl;
-}
-
-void XMLCALL
-XML_SetEntityDeclHandler(XML_Parser parser,
-                         XML_EntityDeclHandler handler)
-{
-  entityDeclHandler = handler;
-}
-
-void XMLCALL
-XML_SetXmlDeclHandler(XML_Parser parser,
-                      XML_XmlDeclHandler handler) {
-  xmlDeclHandler = handler;
-}
-
-int XMLCALL
-XML_SetParamEntityParsing(XML_Parser parser,
-                          enum XML_ParamEntityParsing peParsing)
-{
-  /* block after XML_Parse()/XML_ParseBuffer() has been called */
-  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
-    return 0;
-#ifdef XML_DTD
-  paramEntityParsing = peParsing;
-  return 1;
-#else
-  return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
-#endif
-}
-
-int XMLCALL
-XML_SetHashSalt(XML_Parser parser,
-                unsigned long hash_salt)
-{
-  /* block after XML_Parse()/XML_ParseBuffer() has been called */
-  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
-    return 0;
-  hash_secret_salt = hash_salt;
-  return 1;
-}
-
-enum XML_Status XMLCALL
-XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
-{
-  switch (ps_parsing) {
-  case XML_SUSPENDED:
-    errorCode = XML_ERROR_SUSPENDED;
-    return XML_STATUS_ERROR;
-  case XML_FINISHED:
-    errorCode = XML_ERROR_FINISHED;
-    return XML_STATUS_ERROR;
-  case XML_INITIALIZED:
-    if (parentParser == NULL && !startParsing(parser)) {
-      errorCode = XML_ERROR_NO_MEMORY;
-      return XML_STATUS_ERROR;
-    }
-    /* falls through */
-  default:
-    ps_parsing = XML_PARSING;
-  }
-
-  if (len == 0) {
-    ps_finalBuffer = (XML_Bool)isFinal;
-    if (!isFinal)
-      return XML_STATUS_OK;
-    positionPtr = bufferPtr;
-    parseEndPtr = bufferEnd;
-
-    /* If data are left over from last buffer, and we now know that these
-       data are the final chunk of input, then we have to check them again
-       to detect errors based on that fact.
-    */
-    errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
-
-    if (errorCode == XML_ERROR_NONE) {
-      switch (ps_parsing) {
-      case XML_SUSPENDED:
-        XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
-        positionPtr = bufferPtr;
-        return XML_STATUS_SUSPENDED;
-      case XML_INITIALIZED:
-      case XML_PARSING:
-        ps_parsing = XML_FINISHED;
-        /* fall through */
-      default:
-        return XML_STATUS_OK;
-      }
-    }
-    eventEndPtr = eventPtr;
-    processor = errorProcessor;
-    return XML_STATUS_ERROR;
-  }
-#ifndef XML_CONTEXT_BYTES
-  else if (bufferPtr == bufferEnd) {
-    const char *end;
-    int nLeftOver;
-    enum XML_Status result;
-    parseEndByteIndex += len;
-    positionPtr = s;
-    ps_finalBuffer = (XML_Bool)isFinal;
-
-    errorCode = processor(parser, s, parseEndPtr = s + len, &end);
-
-    if (errorCode != XML_ERROR_NONE) {
-      eventEndPtr = eventPtr;
-      processor = errorProcessor;
-      return XML_STATUS_ERROR;
-    }
-    else {
-      switch (ps_parsing) {
-      case XML_SUSPENDED:
-        result = XML_STATUS_SUSPENDED;
-        break;
-      case XML_INITIALIZED:
-      case XML_PARSING:
-        if (isFinal) {
-          ps_parsing = XML_FINISHED;
-          return XML_STATUS_OK;
-        }
-      /* fall through */
-      default:
-        result = XML_STATUS_OK;
-      }
-    }
-
-    XmlUpdatePosition(encoding, positionPtr, end, &position);
-    nLeftOver = s + len - end;
-    if (nLeftOver) {
-      if (buffer == NULL || nLeftOver > bufferLim - buffer) {
-        /* FIXME avoid integer overflow */
-        char *temp;
-        temp = (buffer == NULL
-                ? (char *)MALLOC(len * 2)
-                : (char *)REALLOC(buffer, len * 2));
-        if (temp == NULL) {
-          errorCode = XML_ERROR_NO_MEMORY;
-          eventPtr = eventEndPtr = NULL;
-          processor = errorProcessor;
-          return XML_STATUS_ERROR;
-        }
-        buffer = temp;
-        bufferLim = buffer + len * 2;
-      }
-      memcpy(buffer, end, nLeftOver);
-    }
-    bufferPtr = buffer;
-    bufferEnd = buffer + nLeftOver;
-    positionPtr = bufferPtr;
-    parseEndPtr = bufferEnd;
-    eventPtr = bufferPtr;
-    eventEndPtr = bufferPtr;
-    return result;
-  }
-#endif  /* not defined XML_CONTEXT_BYTES */
-  else {
-    void *buff = XML_GetBuffer(parser, len);
-    if (buff == NULL)
-      return XML_STATUS_ERROR;
-    else {
-      memcpy(buff, s, len);
-      return XML_ParseBuffer(parser, len, isFinal);
-    }
-  }
-}
-
-enum XML_Status XMLCALL
-XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
-{
-  const char *start;
-  enum XML_Status result = XML_STATUS_OK;
-
-  switch (ps_parsing) {
-  case XML_SUSPENDED:
-    errorCode = XML_ERROR_SUSPENDED;
-    return XML_STATUS_ERROR;
-  case XML_FINISHED:
-    errorCode = XML_ERROR_FINISHED;
-    return XML_STATUS_ERROR;
-  case XML_INITIALIZED:
-    if (parentParser == NULL && !startParsing(parser)) {
-      errorCode = XML_ERROR_NO_MEMORY;
-      return XML_STATUS_ERROR;
-    }
-    /* falls through */
-  default:
-    ps_parsing = XML_PARSING;
-  }
-
-  start = bufferPtr;
-  positionPtr = start;
-  bufferEnd += len;
-  parseEndPtr = bufferEnd;
-  parseEndByteIndex += len;
-  ps_finalBuffer = (XML_Bool)isFinal;
-
-  errorCode = processor(parser, start, parseEndPtr, &bufferPtr);
-
-  if (errorCode != XML_ERROR_NONE) {
-    eventEndPtr = eventPtr;
-    processor = errorProcessor;
-    return XML_STATUS_ERROR;
-  }
-  else {
-    switch (ps_parsing) {
-    case XML_SUSPENDED:
-      result = XML_STATUS_SUSPENDED;
-      break;
-    case XML_INITIALIZED:
-    case XML_PARSING:
-      if (isFinal) {
-        ps_parsing = XML_FINISHED;
-        return result;
-      }
-    default: ;  /* should not happen */
-    }
-  }
-
-  XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
-  positionPtr = bufferPtr;
-  return result;
-}
-
-void * XMLCALL
-XML_GetBuffer(XML_Parser parser, int len)
-{
-  if (len < 0) {
-    errorCode = XML_ERROR_NO_MEMORY;
-    return NULL;
-  }
-  switch (ps_parsing) {
-  case XML_SUSPENDED:
-    errorCode = XML_ERROR_SUSPENDED;
-    return NULL;
-  case XML_FINISHED:
-    errorCode = XML_ERROR_FINISHED;
-    return NULL;
-  default: ;
-  }
-
-  if (len > bufferLim - bufferEnd) {
-#ifdef XML_CONTEXT_BYTES
-    int keep;
-#endif  /* defined XML_CONTEXT_BYTES */
-    /* Do not invoke signed arithmetic overflow: */
-    int neededSize = (int) ((unsigned)len + (unsigned)(bufferEnd - bufferPtr));
-    if (neededSize < 0) {
-      errorCode = XML_ERROR_NO_MEMORY;
-      return NULL;
-    }
-#ifdef XML_CONTEXT_BYTES
-    keep = (int)(bufferPtr - buffer);
-    if (keep > XML_CONTEXT_BYTES)
-      keep = XML_CONTEXT_BYTES;
-    neededSize += keep;
-#endif  /* defined XML_CONTEXT_BYTES */
-    if (neededSize  <= bufferLim - buffer) {
-#ifdef XML_CONTEXT_BYTES
-      if (keep < bufferPtr - buffer) {
-        int offset = (int)(bufferPtr - buffer) - keep;
-        memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
-        bufferEnd -= offset;
-        bufferPtr -= offset;
-      }
-#else
-      memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
-      bufferEnd = buffer + (bufferEnd - bufferPtr);
-      bufferPtr = buffer;
-#endif  /* not defined XML_CONTEXT_BYTES */
-    }
-    else {
-      char *newBuf;
-      int bufferSize = (int)(bufferLim - bufferPtr);
-      if (bufferSize == 0)
-        bufferSize = INIT_BUFFER_SIZE;
-      do {
-        /* Do not invoke signed arithmetic overflow: */
-        bufferSize = (int) (2U * (unsigned) bufferSize);
-      } while (bufferSize < neededSize && bufferSize > 0);
-      if (bufferSize <= 0) {
-        errorCode = XML_ERROR_NO_MEMORY;
-        return NULL;
-      }
-      newBuf = (char *)MALLOC(bufferSize);
-      if (newBuf == 0) {
-        errorCode = XML_ERROR_NO_MEMORY;
-        return NULL;
-      }
-      bufferLim = newBuf + bufferSize;
-#ifdef XML_CONTEXT_BYTES
-      if (bufferPtr) {
-        int keep = (int)(bufferPtr - buffer);
-        if (keep > XML_CONTEXT_BYTES)
-          keep = XML_CONTEXT_BYTES;
-        memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep);
-        FREE(buffer);
-        buffer = newBuf;
-        bufferEnd = buffer + (bufferEnd - bufferPtr) + keep;
-        bufferPtr = buffer + keep;
-      }
-      else {
-        bufferEnd = newBuf + (bufferEnd - bufferPtr);
-        bufferPtr = buffer = newBuf;
-      }
-#else
-      if (bufferPtr) {
-        memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
-        FREE(buffer);
-      }
-      bufferEnd = newBuf + (bufferEnd - bufferPtr);
-      bufferPtr = buffer = newBuf;
-#endif  /* not defined XML_CONTEXT_BYTES */
-    }
-    eventPtr = eventEndPtr = NULL;
-    positionPtr = NULL;
-  }
-  return bufferEnd;
-}
-
-enum XML_Status XMLCALL
-XML_StopParser(XML_Parser parser, XML_Bool resumable)
-{
-  switch (ps_parsing) {
-  case XML_SUSPENDED:
-    if (resumable) {
-      errorCode = XML_ERROR_SUSPENDED;
-      return XML_STATUS_ERROR;
-    }
-    ps_parsing = XML_FINISHED;
-    break;
-  case XML_FINISHED:
-    errorCode = XML_ERROR_FINISHED;
-    return XML_STATUS_ERROR;
-  default:
-    if (resumable) {
-#ifdef XML_DTD
-      if (isParamEntity) {
-        errorCode = XML_ERROR_SUSPEND_PE;
-        return XML_STATUS_ERROR;
-      }
-#endif
-      ps_parsing = XML_SUSPENDED;
-    }
-    else
-      ps_parsing = XML_FINISHED;
-  }
-  return XML_STATUS_OK;
-}
-
-enum XML_Status XMLCALL
-XML_ResumeParser(XML_Parser parser)
-{
-  enum XML_Status result = XML_STATUS_OK;
-
-  if (ps_parsing != XML_SUSPENDED) {
-    errorCode = XML_ERROR_NOT_SUSPENDED;
-    return XML_STATUS_ERROR;
-  }
-  ps_parsing = XML_PARSING;
-
-  errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
-
-  if (errorCode != XML_ERROR_NONE) {
-    eventEndPtr = eventPtr;
-    processor = errorProcessor;
-    return XML_STATUS_ERROR;
-  }
-  else {
-    switch (ps_parsing) {
-    case XML_SUSPENDED:
-      result = XML_STATUS_SUSPENDED;
-      break;
-    case XML_INITIALIZED:
-    case XML_PARSING:
-      if (ps_finalBuffer) {
-        ps_parsing = XML_FINISHED;
-        return result;
-      }
-    default: ;
-    }
-  }
-
-  XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
-  positionPtr = bufferPtr;
-  return result;
-}
-
-void XMLCALL
-XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status)
-{
-  assert(status != NULL);
-  *status = parser->m_parsingStatus;
-}
-
-enum XML_Error XMLCALL
-XML_GetErrorCode(XML_Parser parser)
-{
-  return errorCode;
-}
-
-XML_Index XMLCALL
-XML_GetCurrentByteIndex(XML_Parser parser)
-{
-  if (eventPtr)
-    return (XML_Index)(parseEndByteIndex - (parseEndPtr - eventPtr));
-  return -1;
-}
-
-int XMLCALL
-XML_GetCurrentByteCount(XML_Parser parser)
-{
-  if (eventEndPtr && eventPtr)
-    return (int)(eventEndPtr - eventPtr);
-  return 0;
-}
-
-const char * XMLCALL
-XML_GetInputContext(XML_Parser parser, int *offset, int *size)
-{
-#ifdef XML_CONTEXT_BYTES
-  if (eventPtr && buffer) {
-    *offset = (int)(eventPtr - buffer);
-    *size   = (int)(bufferEnd - buffer);
-    return buffer;
-  }
-#endif /* defined XML_CONTEXT_BYTES */
-  return (char *) 0;
-}
-
-XML_Size XMLCALL
-XML_GetCurrentLineNumber(XML_Parser parser)
-{
-  if (eventPtr && eventPtr >= positionPtr) {
-    XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
-    positionPtr = eventPtr;
-  }
-  return position.lineNumber + 1;
-}
-
-XML_Size XMLCALL
-XML_GetCurrentColumnNumber(XML_Parser parser)
-{
-  if (eventPtr && eventPtr >= positionPtr) {
-    XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
-    positionPtr = eventPtr;
-  }
-  return position.columnNumber;
-}
-
-void XMLCALL
-XML_FreeContentModel(XML_Parser parser, XML_Content *model)
-{
-  FREE(model);
-}
-
-void * XMLCALL
-XML_MemMalloc(XML_Parser parser, size_t size)
-{
-  return MALLOC(size);
-}
-
-void * XMLCALL
-XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
-{
-  return REALLOC(ptr, size);
-}
-
-void XMLCALL
-XML_MemFree(XML_Parser parser, void *ptr)
-{
-  FREE(ptr);
-}
-
-void XMLCALL
-XML_DefaultCurrent(XML_Parser parser)
-{
-  if (defaultHandler) {
-    if (openInternalEntities)
-      reportDefault(parser,
-                    internalEncoding,
-                    openInternalEntities->internalEventPtr,
-                    openInternalEntities->internalEventEndPtr);
-    else
-      reportDefault(parser, encoding, eventPtr, eventEndPtr);
-  }
-}
-
-const XML_LChar * XMLCALL
-XML_ErrorString(enum XML_Error code)
-{
-  static const XML_LChar* const message[] = {
-    0,
-    XML_L("out of memory"),
-    XML_L("syntax error"),
-    XML_L("no element found"),
-    XML_L("not well-formed (invalid token)"),
-    XML_L("unclosed token"),
-    XML_L("partial character"),
-    XML_L("mismatched tag"),
-    XML_L("duplicate attribute"),
-    XML_L("junk after document element"),
-    XML_L("illegal parameter entity reference"),
-    XML_L("undefined entity"),
-    XML_L("recursive entity reference"),
-    XML_L("asynchronous entity"),
-    XML_L("reference to invalid character number"),
-    XML_L("reference to binary entity"),
-    XML_L("reference to external entity in attribute"),
-    XML_L("XML or text declaration not at start of entity"),
-    XML_L("unknown encoding"),
-    XML_L("encoding specified in XML declaration is incorrect"),
-    XML_L("unclosed CDATA section"),
-    XML_L("error in processing external entity reference"),
-    XML_L("document is not standalone"),
-    XML_L("unexpected parser state - please send a bug report"),
-    XML_L("entity declared in parameter entity"),
-    XML_L("requested feature requires XML_DTD support in Expat"),
-    XML_L("cannot change setting once parsing has begun"),
-    XML_L("unbound prefix"),
-    XML_L("must not undeclare prefix"),
-    XML_L("incomplete markup in parameter entity"),
-    XML_L("XML declaration not well-formed"),
-    XML_L("text declaration not well-formed"),
-    XML_L("illegal character(s) in public id"),
-    XML_L("parser suspended"),
-    XML_L("parser not suspended"),
-    XML_L("parsing aborted"),
-    XML_L("parsing finished"),
-    XML_L("cannot suspend in external parameter entity"),
-    XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"),
-    XML_L("reserved prefix (xmlns) must not be declared or undeclared"),
-    XML_L("prefix must not be bound to one of the reserved namespace names")
-  };
-  if (code > 0 && code < sizeof(message)/sizeof(message[0]))
-    return message[code];
-  return NULL;
-}
-
-const XML_LChar * XMLCALL
-XML_ExpatVersion(void) {
-
-  /* V1 is used to string-ize the version number. However, it would
-     string-ize the actual version macro *names* unless we get them
-     substituted before being passed to V1. CPP is defined to expand
-     a macro, then rescan for more expansions. Thus, we use V2 to expand
-     the version macros, then CPP will expand the resulting V1() macro
-     with the correct numerals. */
-  /* ### I'm assuming cpp is portable in this respect... */
-
-#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c)
-#define V2(a,b,c) XML_L("expat_")V1(a,b,c)
-
-  return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION);
-
-#undef V1
-#undef V2
-}
-
-XML_Expat_Version XMLCALL
-XML_ExpatVersionInfo(void)
-{
-  XML_Expat_Version version;
-
-  version.major = XML_MAJOR_VERSION;
-  version.minor = XML_MINOR_VERSION;
-  version.micro = XML_MICRO_VERSION;
-
-  return version;
-}
-
-const XML_Feature * XMLCALL
-XML_GetFeatureList(void)
-{
-  static const XML_Feature features[] = {
-    {XML_FEATURE_SIZEOF_XML_CHAR,  XML_L("sizeof(XML_Char)"),
-     sizeof(XML_Char)},
-    {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
-     sizeof(XML_LChar)},
-#ifdef XML_UNICODE
-    {XML_FEATURE_UNICODE,          XML_L("XML_UNICODE"), 0},
-#endif
-#ifdef XML_UNICODE_WCHAR_T
-    {XML_FEATURE_UNICODE_WCHAR_T,  XML_L("XML_UNICODE_WCHAR_T"), 0},
-#endif
-#ifdef XML_DTD
-    {XML_FEATURE_DTD,              XML_L("XML_DTD"), 0},
-#endif
-#ifdef XML_CONTEXT_BYTES
-    {XML_FEATURE_CONTEXT_BYTES,    XML_L("XML_CONTEXT_BYTES"),
-     XML_CONTEXT_BYTES},
-#endif
-#ifdef XML_MIN_SIZE
-    {XML_FEATURE_MIN_SIZE,         XML_L("XML_MIN_SIZE"), 0},
-#endif
-#ifdef XML_NS
-    {XML_FEATURE_NS,               XML_L("XML_NS"), 0},
-#endif
-#ifdef XML_LARGE_SIZE
-    {XML_FEATURE_LARGE_SIZE,       XML_L("XML_LARGE_SIZE"), 0},
-#endif
-#ifdef XML_ATTR_INFO
-    {XML_FEATURE_ATTR_INFO,        XML_L("XML_ATTR_INFO"), 0},
-#endif
-    {XML_FEATURE_END,              NULL, 0}
-  };
-
-  return features;
-}
-
-/* Initially tag->rawName always points into the parse buffer;
-   for those TAG instances opened while the current parse buffer was
-   processed, and not yet closed, we need to store tag->rawName in a more
-   permanent location, since the parse buffer is about to be discarded.
-*/
-static XML_Bool
-storeRawNames(XML_Parser parser)
-{
-  TAG *tag = tagStack;
-  while (tag) {
-    int bufSize;
-    int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
-    char *rawNameBuf = tag->buf + nameLen;
-    /* Stop if already stored.  Since tagStack is a stack, we can stop
-       at the first entry that has already been copied; everything
-       below it in the stack is already been accounted for in a
-       previous call to this function.
-    */
-    if (tag->rawName == rawNameBuf)
-      break;
-    /* For re-use purposes we need to ensure that the
-       size of tag->buf is a multiple of sizeof(XML_Char).
-    */
-    bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
-    if (bufSize > tag->bufEnd - tag->buf) {
-      char *temp = (char *)REALLOC(tag->buf, bufSize);
-      if (temp == NULL)
-        return XML_FALSE;
-      /* if tag->name.str points to tag->buf (only when namespace
-         processing is off) then we have to update it
-      */
-      if (tag->name.str == (XML_Char *)tag->buf)
-        tag->name.str = (XML_Char *)temp;
-      /* if tag->name.localPart is set (when namespace processing is on)
-         then update it as well, since it will always point into tag->buf
-      */
-      if (tag->name.localPart)
-        tag->name.localPart = (XML_Char *)temp + (tag->name.localPart -
-                                                  (XML_Char *)tag->buf);
-      tag->buf = temp;
-      tag->bufEnd = temp + bufSize;
-      rawNameBuf = temp + nameLen;
-    }
-    memcpy(rawNameBuf, tag->rawName, tag->rawNameLength);
-    tag->rawName = rawNameBuf;
-    tag = tag->parent;
-  }
-  return XML_TRUE;
-}
-
-static enum XML_Error PTRCALL
-contentProcessor(XML_Parser parser,
-                 const char *start,
-                 const char *end,
-                 const char **endPtr)
-{
-  enum XML_Error result = doContent(parser, 0, encoding, start, end,
-                                    endPtr, (XML_Bool)!ps_finalBuffer);
-  if (result == XML_ERROR_NONE) {
-    if (!storeRawNames(parser))
-      return XML_ERROR_NO_MEMORY;
-  }
-  return result;
-}
-
-static enum XML_Error PTRCALL
-externalEntityInitProcessor(XML_Parser parser,
-                            const char *start,
-                            const char *end,
-                            const char **endPtr)
-{
-  enum XML_Error result = initializeEncoding(parser);
-  if (result != XML_ERROR_NONE)
-    return result;
-  processor = externalEntityInitProcessor2;
-  return externalEntityInitProcessor2(parser, start, end, endPtr);
-}
-
-static enum XML_Error PTRCALL
-externalEntityInitProcessor2(XML_Parser parser,
-                             const char *start,
-                             const char *end,
-                             const char **endPtr)
-{
-  const char *next = start; /* XmlContentTok doesn't always set the last arg */
-  int tok = XmlContentTok(encoding, start, end, &next);
-  switch (tok) {
-  case XML_TOK_BOM:
-    /* If we are at the end of the buffer, this would cause the next stage,
-       i.e. externalEntityInitProcessor3, to pass control directly to
-       doContent (by detecting XML_TOK_NONE) without processing any xml text
-       declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
-    */
-    if (next == end && !ps_finalBuffer) {
-      *endPtr = next;
-      return XML_ERROR_NONE;
-    }
-    start = next;
-    break;
-  case XML_TOK_PARTIAL:
-    if (!ps_finalBuffer) {
-      *endPtr = start;
-      return XML_ERROR_NONE;
-    }
-    eventPtr = start;
-    return XML_ERROR_UNCLOSED_TOKEN;
-  case XML_TOK_PARTIAL_CHAR:
-    if (!ps_finalBuffer) {
-      *endPtr = start;
-      return XML_ERROR_NONE;
-    }
-    eventPtr = start;
-    return XML_ERROR_PARTIAL_CHAR;
-  }
-  processor = externalEntityInitProcessor3;
-  return externalEntityInitProcessor3(parser, start, end, endPtr);
-}
-
-static enum XML_Error PTRCALL
-externalEntityInitProcessor3(XML_Parser parser,
-                             const char *start,
-                             const char *end,
-                             const char **endPtr)
-{
-  int tok;
-  const char *next = start; /* XmlContentTok doesn't always set the last arg */
-  eventPtr = start;
-  tok = XmlContentTok(encoding, start, end, &next);
-  eventEndPtr = next;
-
-  switch (tok) {
-  case XML_TOK_XML_DECL:
-    {
-      enum XML_Error result;
-      result = processXmlDecl(parser, 1, start, next);
-      if (result != XML_ERROR_NONE)
-        return result;
-      switch (ps_parsing) {
-      case XML_SUSPENDED:
-        *endPtr = next;
-        return XML_ERROR_NONE;
-      case XML_FINISHED:
-        return XML_ERROR_ABORTED;
-      default:
-        start = next;
-      }
-    }
-    break;
-  case XML_TOK_PARTIAL:
-    if (!ps_finalBuffer) {
-      *endPtr = start;
-      return XML_ERROR_NONE;
-    }
-    return XML_ERROR_UNCLOSED_TOKEN;
-  case XML_TOK_PARTIAL_CHAR:
-    if (!ps_finalBuffer) {
-      *endPtr = start;
-      return XML_ERROR_NONE;
-    }
-    return XML_ERROR_PARTIAL_CHAR;
-  }
-  processor = externalEntityContentProcessor;
-  tagLevel = 1;
-  return externalEntityContentProcessor(parser, start, end, endPtr);
-}
-
-static enum XML_Error PTRCALL
-externalEntityContentProcessor(XML_Parser parser,
-                               const char *start,
-                               const char *end,
-                               const char **endPtr)
-{
-  enum XML_Error result = doContent(parser, 1, encoding, start, end,
-                                    endPtr, (XML_Bool)!ps_finalBuffer);
-  if (result == XML_ERROR_NONE) {
-    if (!storeRawNames(parser))
-      return XML_ERROR_NO_MEMORY;
-  }
-  return result;
-}
-
-static enum XML_Error
-doContent(XML_Parser parser,
-          int startTagLevel,
-          const ENCODING *enc,
-          const char *s,
-          const char *end,
-          const char **nextPtr,
-          XML_Bool haveMore)
-{
-  /* save one level of indirection */
-  DTD * const dtd = _dtd;
-
-  const char **eventPP;
-  const char **eventEndPP;
-  if (enc == encoding) {
-    eventPP = &eventPtr;
-    eventEndPP = &eventEndPtr;
-  }
-  else {
-    eventPP = &(openInternalEntities->internalEventPtr);
-    eventEndPP = &(openInternalEntities->internalEventEndPtr);
-  }
-  *eventPP = s;
-
-  for (;;) {
-    const char *next = s; /* XmlContentTok doesn't always set the last arg */
-    int tok = XmlContentTok(enc, s, end, &next);
-    *eventEndPP = next;
-    switch (tok) {
-    case XML_TOK_TRAILING_CR:
-      if (haveMore) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      *eventEndPP = end;
-      if (characterDataHandler) {
-        XML_Char c = 0xA;
-        characterDataHandler(handlerArg, &c, 1);
-      }
-      else if (defaultHandler)
-        reportDefault(parser, enc, s, end);
-      /* We are at the end of the final buffer, should we check for
-         XML_SUSPENDED, XML_FINISHED?
-      */
-      if (startTagLevel == 0)
-        return XML_ERROR_NO_ELEMENTS;
-      if (tagLevel != startTagLevel)
-        return XML_ERROR_ASYNC_ENTITY;
-      *nextPtr = end;
-      return XML_ERROR_NONE;
-    case XML_TOK_NONE:
-      if (haveMore) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      if (startTagLevel > 0) {
-        if (tagLevel != startTagLevel)
-          return XML_ERROR_ASYNC_ENTITY;
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      return XML_ERROR_NO_ELEMENTS;
-    case XML_TOK_INVALID:
-      *eventPP = next;
-      return XML_ERROR_INVALID_TOKEN;
-    case XML_TOK_PARTIAL:
-      if (haveMore) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      return XML_ERROR_UNCLOSED_TOKEN;
-    case XML_TOK_PARTIAL_CHAR:
-      if (haveMore) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      return XML_ERROR_PARTIAL_CHAR;
-    case XML_TOK_ENTITY_REF:
-      {
-        const XML_Char *name;
-        ENTITY *entity;
-        XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
-                                              s + enc->minBytesPerChar,
-                                              next - enc->minBytesPerChar);
-        if (ch) {
-          if (characterDataHandler)
-            characterDataHandler(handlerArg, &ch, 1);
-          else if (defaultHandler)
-            reportDefault(parser, enc, s, next);
-          break;
-        }
-        name = poolStoreString(&dtd->pool, enc,
-                                s + enc->minBytesPerChar,
-                                next - enc->minBytesPerChar);
-        if (!name)
-          return XML_ERROR_NO_MEMORY;
-        entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
-        poolDiscard(&dtd->pool);
-        /* First, determine if a check for an existing declaration is needed;
-           if yes, check that the entity exists, and that it is internal,
-           otherwise call the skipped entity or default handler.
-        */
-        if (!dtd->hasParamEntityRefs || dtd->standalone) {
-          if (!entity)
-            return XML_ERROR_UNDEFINED_ENTITY;
-          else if (!entity->is_internal)
-            return XML_ERROR_ENTITY_DECLARED_IN_PE;
-        }
-        else if (!entity) {
-          if (skippedEntityHandler)
-            skippedEntityHandler(handlerArg, name, 0);
-          else if (defaultHandler)
-            reportDefault(parser, enc, s, next);
-          break;
-        }
-        if (entity->open)
-          return XML_ERROR_RECURSIVE_ENTITY_REF;
-        if (entity->notation)
-          return XML_ERROR_BINARY_ENTITY_REF;
-        if (entity->textPtr) {
-          enum XML_Error result;
-          if (!defaultExpandInternalEntities) {
-            if (skippedEntityHandler)
-              skippedEntityHandler(handlerArg, entity->name, 0);
-            else if (defaultHandler)
-              reportDefault(parser, enc, s, next);
-            break;
-          }
-          result = processInternalEntity(parser, entity, XML_FALSE);
-          if (result != XML_ERROR_NONE)
-            return result;
-        }
-        else if (externalEntityRefHandler) {
-          const XML_Char *context;
-          entity->open = XML_TRUE;
-          context = getContext(parser);
-          entity->open = XML_FALSE;
-          if (!context)
-            return XML_ERROR_NO_MEMORY;
-          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
-                                        context,
-                                        entity->base,
-                                        entity->systemId,
-                                        entity->publicId))
-            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
-          poolDiscard(&tempPool);
-        }
-        else if (defaultHandler)
-          reportDefault(parser, enc, s, next);
-        break;
-      }
-    case XML_TOK_START_TAG_NO_ATTS:
-      /* fall through */
-    case XML_TOK_START_TAG_WITH_ATTS:
-      {
-        TAG *tag;
-        enum XML_Error result;
-        XML_Char *toPtr;
-        if (freeTagList) {
-          tag = freeTagList;
-          freeTagList = freeTagList->parent;
-        }
-        else {
-          tag = (TAG *)MALLOC(sizeof(TAG));
-          if (!tag)
-            return XML_ERROR_NO_MEMORY;
-          tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE);
-          if (!tag->buf) {
-            FREE(tag);
-            return XML_ERROR_NO_MEMORY;
-          }
-          tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
-        }
-        tag->bindings = NULL;
-        tag->parent = tagStack;
-        tagStack = tag;
-        tag->name.localPart = NULL;
-        tag->name.prefix = NULL;
-        tag->rawName = s + enc->minBytesPerChar;
-        tag->rawNameLength = XmlNameLength(enc, tag->rawName);
-        ++tagLevel;
-        {
-          const char *rawNameEnd = tag->rawName + tag->rawNameLength;
-          const char *fromPtr = tag->rawName;
-          toPtr = (XML_Char *)tag->buf;
-          for (;;) {
-            int bufSize;
-            int convLen;
-            const enum XML_Convert_Result convert_res = XmlConvert(enc,
-                       &fromPtr, rawNameEnd,
-                       (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
-            convLen = (int)(toPtr - (XML_Char *)tag->buf);
-            if ((fromPtr >= rawNameEnd) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) {
-              tag->name.strLen = convLen;
-              break;
-            }
-            bufSize = (int)(tag->bufEnd - tag->buf) << 1;
-            {
-              char *temp = (char *)REALLOC(tag->buf, bufSize);
-              if (temp == NULL)
-                return XML_ERROR_NO_MEMORY;
-              tag->buf = temp;
-              tag->bufEnd = temp + bufSize;
-              toPtr = (XML_Char *)temp + convLen;
-            }
-          }
-        }
-        tag->name.str = (XML_Char *)tag->buf;
-        *toPtr = XML_T('\0');
-        result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
-        if (result)
-          return result;
-        if (startElementHandler)
-          startElementHandler(handlerArg, tag->name.str,
-                              (const XML_Char **)atts);
-        else if (defaultHandler)
-          reportDefault(parser, enc, s, next);
-        poolClear(&tempPool);
-        break;
-      }
-    case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
-      /* fall through */
-    case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
-      {
-        const char *rawName = s + enc->minBytesPerChar;
-        enum XML_Error result;
-        BINDING *bindings = NULL;
-        XML_Bool noElmHandlers = XML_TRUE;
-        TAG_NAME name;
-        name.str = poolStoreString(&tempPool, enc, rawName,
-                                   rawName + XmlNameLength(enc, rawName));
-        if (!name.str)
-          return XML_ERROR_NO_MEMORY;
-        poolFinish(&tempPool);
-        result = storeAtts(parser, enc, s, &name, &bindings);
-        if (result)
-          return result;
-        poolFinish(&tempPool);
-        if (startElementHandler) {
-          startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
-          noElmHandlers = XML_FALSE;
-        }
-        if (endElementHandler) {
-          if (startElementHandler)
-            *eventPP = *eventEndPP;
-          endElementHandler(handlerArg, name.str);
-          noElmHandlers = XML_FALSE;
-        }
-        if (noElmHandlers && defaultHandler)
-          reportDefault(parser, enc, s, next);
-        poolClear(&tempPool);
-        while (bindings) {
-          BINDING *b = bindings;
-          if (endNamespaceDeclHandler)
-            endNamespaceDeclHandler(handlerArg, b->prefix->name);
-          bindings = bindings->nextTagBinding;
-          b->nextTagBinding = freeBindingList;
-          freeBindingList = b;
-          b->prefix->binding = b->prevPrefixBinding;
-        }
-      }
-      if (tagLevel == 0)
-        return epilogProcessor(parser, next, end, nextPtr);
-      break;
-    case XML_TOK_END_TAG:
-      if (tagLevel == startTagLevel)
-        return XML_ERROR_ASYNC_ENTITY;
-      else {
-        int len;
-        const char *rawName;
-        TAG *tag = tagStack;
-        tagStack = tag->parent;
-        tag->parent = freeTagList;
-        freeTagList = tag;
-        rawName = s + enc->minBytesPerChar*2;
-        len = XmlNameLength(enc, rawName);
-        if (len != tag->rawNameLength
-            || memcmp(tag->rawName, rawName, len) != 0) {
-          *eventPP = rawName;
-          return XML_ERROR_TAG_MISMATCH;
-        }
-        --tagLevel;
-        if (endElementHandler) {
-          const XML_Char *localPart;
-          const XML_Char *prefix;
-          XML_Char *uri;
-          localPart = tag->name.localPart;
-          if (ns && localPart) {
-            /* localPart and prefix may have been overwritten in
-               tag->name.str, since this points to the binding->uri
-               buffer which gets re-used; so we have to add them again
-            */
-            uri = (XML_Char *)tag->name.str + tag->name.uriLen;
-            /* don't need to check for space - already done in storeAtts() */
-            while (*localPart) *uri++ = *localPart++;
-            prefix = (XML_Char *)tag->name.prefix;
-            if (ns_triplets && prefix) {
-              *uri++ = namespaceSeparator;
-              while (*prefix) *uri++ = *prefix++;
-             }
-            *uri = XML_T('\0');
-          }
-          endElementHandler(handlerArg, tag->name.str);
-        }
-        else if (defaultHandler)
-          reportDefault(parser, enc, s, next);
-        while (tag->bindings) {
-          BINDING *b = tag->bindings;
-          if (endNamespaceDeclHandler)
-            endNamespaceDeclHandler(handlerArg, b->prefix->name);
-          tag->bindings = tag->bindings->nextTagBinding;
-          b->nextTagBinding = freeBindingList;
-          freeBindingList = b;
-          b->prefix->binding = b->prevPrefixBinding;
-        }
-        if (tagLevel == 0)
-          return epilogProcessor(parser, next, end, nextPtr);
-      }
-      break;
-    case XML_TOK_CHAR_REF:
-      {
-        int n = XmlCharRefNumber(enc, s);
-        if (n < 0)
-          return XML_ERROR_BAD_CHAR_REF;
-        if (characterDataHandler) {
-          XML_Char buf[XML_ENCODE_MAX];
-          characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
-        }
-        else if (defaultHandler)
-          reportDefault(parser, enc, s, next);
-      }
-      break;
-    case XML_TOK_XML_DECL:
-      return XML_ERROR_MISPLACED_XML_PI;
-    case XML_TOK_DATA_NEWLINE:
-      if (characterDataHandler) {
-        XML_Char c = 0xA;
-        characterDataHandler(handlerArg, &c, 1);
-      }
-      else if (defaultHandler)
-        reportDefault(parser, enc, s, next);
-      break;
-    case XML_TOK_CDATA_SECT_OPEN:
-      {
-        enum XML_Error result;
-        if (startCdataSectionHandler)
-          startCdataSectionHandler(handlerArg);
-#if 0
-        /* Suppose you doing a transformation on a document that involves
-           changing only the character data.  You set up a defaultHandler
-           and a characterDataHandler.  The defaultHandler simply copies
-           characters through.  The characterDataHandler does the
-           transformation and writes the characters out escaping them as
-           necessary.  This case will fail to work if we leave out the
-           following two lines (because & and < inside CDATA sections will
-           be incorrectly escaped).
-
-           However, now we have a start/endCdataSectionHandler, so it seems
-           easier to let the user deal with this.
-        */
-        else if (characterDataHandler)
-          characterDataHandler(handlerArg, dataBuf, 0);
-#endif
-        else if (defaultHandler)
-          reportDefault(parser, enc, s, next);
-        result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
-        if (result != XML_ERROR_NONE)
-          return result;
-        else if (!next) {
-          processor = cdataSectionProcessor;
-          return result;
-        }
-      }
-      break;
-    case XML_TOK_TRAILING_RSQB:
-      if (haveMore) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      if (characterDataHandler) {
-        if (MUST_CONVERT(enc, s)) {
-          ICHAR *dataPtr = (ICHAR *)dataBuf;
-          XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
-          characterDataHandler(handlerArg, dataBuf,
-                               (int)(dataPtr - (ICHAR *)dataBuf));
-        }
-        else
-          characterDataHandler(handlerArg,
-                               (XML_Char *)s,
-                               (int)((XML_Char *)end - (XML_Char *)s));
-      }
-      else if (defaultHandler)
-        reportDefault(parser, enc, s, end);
-      /* We are at the end of the final buffer, should we check for
-         XML_SUSPENDED, XML_FINISHED?
-      */
-      if (startTagLevel == 0) {
-        *eventPP = end;
-        return XML_ERROR_NO_ELEMENTS;
-      }
-      if (tagLevel != startTagLevel) {
-        *eventPP = end;
-        return XML_ERROR_ASYNC_ENTITY;
-      }
-      *nextPtr = end;
-      return XML_ERROR_NONE;
-    case XML_TOK_DATA_CHARS:
-      {
-        XML_CharacterDataHandler charDataHandler = characterDataHandler;
-        if (charDataHandler) {
-          if (MUST_CONVERT(enc, s)) {
-            for (;;) {
-              ICHAR *dataPtr = (ICHAR *)dataBuf;
-              const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
-              *eventEndPP = s;
-              charDataHandler(handlerArg, dataBuf,
-                              (int)(dataPtr - (ICHAR *)dataBuf));
-              if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
-                break;
-              *eventPP = s;
-            }
-          }
-          else
-            charDataHandler(handlerArg,
-                            (XML_Char *)s,
-                            (int)((XML_Char *)next - (XML_Char *)s));
-        }
-        else if (defaultHandler)
-          reportDefault(parser, enc, s, next);
-      }
-      break;
-    case XML_TOK_PI:
-      if (!reportProcessingInstruction(parser, enc, s, next))
-        return XML_ERROR_NO_MEMORY;
-      break;
-    case XML_TOK_COMMENT:
-      if (!reportComment(parser, enc, s, next))
-        return XML_ERROR_NO_MEMORY;
-      break;
-    default:
-      if (defaultHandler)
-        reportDefault(parser, enc, s, next);
-      break;
-    }
-    *eventPP = s = next;
-    switch (ps_parsing) {
-    case XML_SUSPENDED:
-      *nextPtr = next;
-      return XML_ERROR_NONE;
-    case XML_FINISHED:
-      return XML_ERROR_ABORTED;
-    default: ;
-    }
-  }
-  /* not reached */
-}
-
-/* Precondition: all arguments must be non-NULL;
-   Purpose:
-   - normalize attributes
-   - check attributes for well-formedness
-   - generate namespace aware attribute names (URI, prefix)
-   - build list of attributes for startElementHandler
-   - default attributes
-   - process namespace declarations (check and report them)
-   - generate namespace aware element name (URI, prefix)
-*/
-static enum XML_Error
-storeAtts(XML_Parser parser, const ENCODING *enc,
-          const char *attStr, TAG_NAME *tagNamePtr,
-          BINDING **bindingsPtr)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  ELEMENT_TYPE *elementType;
-  int nDefaultAtts;
-  const XML_Char **appAtts;   /* the attribute list for the application */
-  int attIndex = 0;
-  int prefixLen;
-  int i;
-  int n;
-  XML_Char *uri;
-  int nPrefixes = 0;
-  BINDING *binding;
-  const XML_Char *localPart;
-
-  /* lookup the element type name */
-  elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0);
-  if (!elementType) {
-    const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
-    if (!name)
-      return XML_ERROR_NO_MEMORY;
-    elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
-                                         sizeof(ELEMENT_TYPE));
-    if (!elementType)
-      return XML_ERROR_NO_MEMORY;
-    if (ns && !setElementTypePrefix(parser, elementType))
-      return XML_ERROR_NO_MEMORY;
-  }
-  nDefaultAtts = elementType->nDefaultAtts;
-
-  /* get the attributes from the tokenizer */
-  n = XmlGetAttributes(enc, attStr, attsSize, atts);
-  if (n + nDefaultAtts > attsSize) {
-    int oldAttsSize = attsSize;
-    ATTRIBUTE *temp;
-#ifdef XML_ATTR_INFO
-    XML_AttrInfo *temp2;
-#endif
-    attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
-    temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
-    if (temp == NULL)
-      return XML_ERROR_NO_MEMORY;
-    atts = temp;
-#ifdef XML_ATTR_INFO
-    temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo));
-    if (temp2 == NULL)
-      return XML_ERROR_NO_MEMORY;
-    attInfo = temp2;
-#endif
-    if (n > oldAttsSize)
-      XmlGetAttributes(enc, attStr, n, atts);
-  }
-
-  appAtts = (const XML_Char **)atts;
-  for (i = 0; i < n; i++) {
-    ATTRIBUTE *currAtt = &atts[i];
-#ifdef XML_ATTR_INFO
-    XML_AttrInfo *currAttInfo = &attInfo[i];
-#endif
-    /* add the name and value to the attribute list */
-    ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name,
-                                         currAtt->name
-                                         + XmlNameLength(enc, currAtt->name));
-    if (!attId)
-      return XML_ERROR_NO_MEMORY;
-#ifdef XML_ATTR_INFO
-    currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name);
-    currAttInfo->nameEnd = currAttInfo->nameStart +
-                           XmlNameLength(enc, currAtt->name);
-    currAttInfo->valueStart = parseEndByteIndex -
-                            (parseEndPtr - currAtt->valuePtr);
-    currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd);
-#endif
-    /* Detect duplicate attributes by their QNames. This does not work when
-       namespace processing is turned on and different prefixes for the same
-       namespace are used. For this case we have a check further down.
-    */
-    if ((attId->name)[-1]) {
-      if (enc == encoding)
-        eventPtr = atts[i].name;
-      return XML_ERROR_DUPLICATE_ATTRIBUTE;
-    }
-    (attId->name)[-1] = 1;
-    appAtts[attIndex++] = attId->name;
-    if (!atts[i].normalized) {
-      enum XML_Error result;
-      XML_Bool isCdata = XML_TRUE;
-
-      /* figure out whether declared as other than CDATA */
-      if (attId->maybeTokenized) {
-        int j;
-        for (j = 0; j < nDefaultAtts; j++) {
-          if (attId == elementType->defaultAtts[j].id) {
-            isCdata = elementType->defaultAtts[j].isCdata;
-            break;
-          }
-        }
-      }
-
-      /* normalize the attribute value */
-      result = storeAttributeValue(parser, enc, isCdata,
-                                   atts[i].valuePtr, atts[i].valueEnd,
-                                   &tempPool);
-      if (result)
-        return result;
-      appAtts[attIndex] = poolStart(&tempPool);
-      poolFinish(&tempPool);
-    }
-    else {
-      /* the value did not need normalizing */
-      appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr,
-                                          atts[i].valueEnd);
-      if (appAtts[attIndex] == 0)
-        return XML_ERROR_NO_MEMORY;
-      poolFinish(&tempPool);
-    }
-    /* handle prefixed attribute names */
-    if (attId->prefix) {
-      if (attId->xmlns) {
-        /* deal with namespace declarations here */
-        enum XML_Error result = addBinding(parser, attId->prefix, attId,
-                                           appAtts[attIndex], bindingsPtr);
-        if (result)
-          return result;
-        --attIndex;
-      }
-      else {
-        /* deal with other prefixed names later */
-        attIndex++;
-        nPrefixes++;
-        (attId->name)[-1] = 2;
-      }
-    }
-    else
-      attIndex++;
-  }
-
-  /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
-  nSpecifiedAtts = attIndex;
-  if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
-    for (i = 0; i < attIndex; i += 2)
-      if (appAtts[i] == elementType->idAtt->name) {
-        idAttIndex = i;
-        break;
-      }
-  }
-  else
-    idAttIndex = -1;
-
-  /* do attribute defaulting */
-  for (i = 0; i < nDefaultAtts; i++) {
-    const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i;
-    if (!(da->id->name)[-1] && da->value) {
-      if (da->id->prefix) {
-        if (da->id->xmlns) {
-          enum XML_Error result = addBinding(parser, da->id->prefix, da->id,
-                                             da->value, bindingsPtr);
-          if (result)
-            return result;
-        }
-        else {
-          (da->id->name)[-1] = 2;
-          nPrefixes++;
-          appAtts[attIndex++] = da->id->name;
-          appAtts[attIndex++] = da->value;
-        }
-      }
-      else {
-        (da->id->name)[-1] = 1;
-        appAtts[attIndex++] = da->id->name;
-        appAtts[attIndex++] = da->value;
-      }
-    }
-  }
-  appAtts[attIndex] = 0;
-
-  /* expand prefixed attribute names, check for duplicates,
-     and clear flags that say whether attributes were specified */
-  i = 0;
-  if (nPrefixes) {
-    int j;  /* hash table index */
-    unsigned long version = nsAttsVersion;
-    int nsAttsSize = (int)1 << nsAttsPower;
-    /* size of hash table must be at least 2 * (# of prefixed attributes) */
-    if ((nPrefixes << 1) >> nsAttsPower) {  /* true for nsAttsPower = 0 */
-      NS_ATT *temp;
-      /* hash table size must also be a power of 2 and >= 8 */
-      while (nPrefixes >> nsAttsPower++);
-      if (nsAttsPower < 3)
-        nsAttsPower = 3;
-      nsAttsSize = (int)1 << nsAttsPower;
-      temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT));
-      if (!temp)
-        return XML_ERROR_NO_MEMORY;
-      nsAtts = temp;
-      version = 0;  /* force re-initialization of nsAtts hash table */
-    }
-    /* using a version flag saves us from initializing nsAtts every time */
-    if (!version) {  /* initialize version flags when version wraps around */
-      version = INIT_ATTS_VERSION;
-      for (j = nsAttsSize; j != 0; )
-        nsAtts[--j].version = version;
-    }
-    nsAttsVersion = --version;
-
-    /* expand prefixed names and check for duplicates */
-    for (; i < attIndex; i += 2) {
-      const XML_Char *s = appAtts[i];
-      if (s[-1] == 2) {  /* prefixed */
-        ATTRIBUTE_ID *id;
-        const BINDING *b;
-        unsigned long uriHash = hash_secret_salt;
-        ((XML_Char *)s)[-1] = 0;  /* clear flag */
-        id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
-        if (!id || !id->prefix)
-          return XML_ERROR_NO_MEMORY;
-        b = id->prefix->binding;
-        if (!b)
-          return XML_ERROR_UNBOUND_PREFIX;
-
-        /* as we expand the name we also calculate its hash value */
-        for (j = 0; j < b->uriLen; j++) {
-          const XML_Char c = b->uri[j];
-          if (!poolAppendChar(&tempPool, c))
-            return XML_ERROR_NO_MEMORY;
-          uriHash = CHAR_HASH(uriHash, c);
-        }
-        while (*s++ != XML_T(ASCII_COLON))
-          ;
-        do {  /* copies null terminator */
-          const XML_Char c = *s;
-          if (!poolAppendChar(&tempPool, *s))
-            return XML_ERROR_NO_MEMORY;
-          uriHash = CHAR_HASH(uriHash, c);
-        } while (*s++);
-
-        { /* Check hash table for duplicate of expanded name (uriName).
-             Derived from code in lookup(parser, HASH_TABLE *table, ...).
-          */
-          unsigned char step = 0;
-          unsigned long mask = nsAttsSize - 1;
-          j = uriHash & mask;  /* index into hash table */
-          while (nsAtts[j].version == version) {
-            /* for speed we compare stored hash values first */
-            if (uriHash == nsAtts[j].hash) {
-              const XML_Char *s1 = poolStart(&tempPool);
-              const XML_Char *s2 = nsAtts[j].uriName;
-              /* s1 is null terminated, but not s2 */
-              for (; *s1 == *s2 && *s1 != 0; s1++, s2++);
-              if (*s1 == 0)
-                return XML_ERROR_DUPLICATE_ATTRIBUTE;
-            }
-            if (!step)
-              step = PROBE_STEP(uriHash, mask, nsAttsPower);
-            j < step ? (j += nsAttsSize - step) : (j -= step);
-          }
-        }
-
-        if (ns_triplets) {  /* append namespace separator and prefix */
-          tempPool.ptr[-1] = namespaceSeparator;
-          s = b->prefix->name;
-          do {
-            if (!poolAppendChar(&tempPool, *s))
-              return XML_ERROR_NO_MEMORY;
-          } while (*s++);
-        }
-
-        /* store expanded name in attribute list */
-        s = poolStart(&tempPool);
-        poolFinish(&tempPool);
-        appAtts[i] = s;
-
-        /* fill empty slot with new version, uriName and hash value */
-        nsAtts[j].version = version;
-        nsAtts[j].hash = uriHash;
-        nsAtts[j].uriName = s;
-
-        if (!--nPrefixes) {
-          i += 2;
-          break;
-        }
-      }
-      else  /* not prefixed */
-        ((XML_Char *)s)[-1] = 0;  /* clear flag */
-    }
-  }
-  /* clear flags for the remaining attributes */
-  for (; i < attIndex; i += 2)
-    ((XML_Char *)(appAtts[i]))[-1] = 0;
-  for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
-    binding->attId->name[-1] = 0;
-
-  if (!ns)
-    return XML_ERROR_NONE;
-
-  /* expand the element type name */
-  if (elementType->prefix) {
-    binding = elementType->prefix->binding;
-    if (!binding)
-      return XML_ERROR_UNBOUND_PREFIX;
-    localPart = tagNamePtr->str;
-    while (*localPart++ != XML_T(ASCII_COLON))
-      ;
-  }
-  else if (dtd->defaultPrefix.binding) {
-    binding = dtd->defaultPrefix.binding;
-    localPart = tagNamePtr->str;
-  }
-  else
-    return XML_ERROR_NONE;
-  prefixLen = 0;
-  if (ns_triplets && binding->prefix->name) {
-    for (; binding->prefix->name[prefixLen++];)
-      ;  /* prefixLen includes null terminator */
-  }
-  tagNamePtr->localPart = localPart;
-  tagNamePtr->uriLen = binding->uriLen;
-  tagNamePtr->prefix = binding->prefix->name;
-  tagNamePtr->prefixLen = prefixLen;
-  for (i = 0; localPart[i++];)
-    ;  /* i includes null terminator */
-  n = i + binding->uriLen + prefixLen;
-  if (n > binding->uriAlloc) {
-    TAG *p;
-    uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
-    if (!uri)
-      return XML_ERROR_NO_MEMORY;
-    binding->uriAlloc = n + EXPAND_SPARE;
-    memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
-    for (p = tagStack; p; p = p->parent)
-      if (p->name.str == binding->uri)
-        p->name.str = uri;
-    FREE(binding->uri);
-    binding->uri = uri;
-  }
-  /* if namespaceSeparator != '\0' then uri includes it already */
-  uri = binding->uri + binding->uriLen;
-  memcpy(uri, localPart, i * sizeof(XML_Char));
-  /* we always have a namespace separator between localPart and prefix */
-  if (prefixLen) {
-    uri += i - 1;
-    *uri = namespaceSeparator;  /* replace null terminator */
-    memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
-  }
-  tagNamePtr->str = binding->uri;
-  return XML_ERROR_NONE;
-}
-
-/* addBinding() overwrites the value of prefix->binding without checking.
-   Therefore one must keep track of the old value outside of addBinding().
-*/
-static enum XML_Error
-addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
-           const XML_Char *uri, BINDING **bindingsPtr)
-{
-  static const XML_Char xmlNamespace[] = {
-    ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
-    ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
-    ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L,
-    ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, ASCII_SLASH,
-    ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
-    ASCII_e, '\0'
-  };
-  static const int xmlLen =
-    (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1;
-  static const XML_Char xmlnsNamespace[] = {
-    ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
-    ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
-    ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0,
-    ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s,
-    ASCII_SLASH, '\0'
-  };
-  static const int xmlnsLen =
-    (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1;
-
-  XML_Bool mustBeXML = XML_FALSE;
-  XML_Bool isXML = XML_TRUE;
-  XML_Bool isXMLNS = XML_TRUE;
-
-  BINDING *b;
-  int len;
-
-  /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */
-  if (*uri == XML_T('\0') && prefix->name)
-    return XML_ERROR_UNDECLARING_PREFIX;
-
-  if (prefix->name
-      && prefix->name[0] == XML_T(ASCII_x)
-      && prefix->name[1] == XML_T(ASCII_m)
-      && prefix->name[2] == XML_T(ASCII_l)) {
-
-    /* Not allowed to bind xmlns */
-    if (prefix->name[3] == XML_T(ASCII_n)
-        && prefix->name[4] == XML_T(ASCII_s)
-        && prefix->name[5] == XML_T('\0'))
-      return XML_ERROR_RESERVED_PREFIX_XMLNS;
-
-    if (prefix->name[3] == XML_T('\0'))
-      mustBeXML = XML_TRUE;
-  }
-
-  for (len = 0; uri[len]; len++) {
-    if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len]))
-      isXML = XML_FALSE;
-
-    if (!mustBeXML && isXMLNS
-        && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
-      isXMLNS = XML_FALSE;
-  }
-  isXML = isXML && len == xmlLen;
-  isXMLNS = isXMLNS && len == xmlnsLen;
-
-  if (mustBeXML != isXML)
-    return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML
-                     : XML_ERROR_RESERVED_NAMESPACE_URI;
-
-  if (isXMLNS)
-    return XML_ERROR_RESERVED_NAMESPACE_URI;
-
-  if (namespaceSeparator)
-    len++;
-  if (freeBindingList) {
-    b = freeBindingList;
-    if (len > b->uriAlloc) {
-      XML_Char *temp = (XML_Char *)REALLOC(b->uri,
-                          sizeof(XML_Char) * (len + EXPAND_SPARE));
-      if (temp == NULL)
-        return XML_ERROR_NO_MEMORY;
-      b->uri = temp;
-      b->uriAlloc = len + EXPAND_SPARE;
-    }
-    freeBindingList = b->nextTagBinding;
-  }
-  else {
-    b = (BINDING *)MALLOC(sizeof(BINDING));
-    if (!b)
-      return XML_ERROR_NO_MEMORY;
-    b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
-    if (!b->uri) {
-      FREE(b);
-      return XML_ERROR_NO_MEMORY;
-    }
-    b->uriAlloc = len + EXPAND_SPARE;
-  }
-  b->uriLen = len;
-  memcpy(b->uri, uri, len * sizeof(XML_Char));
-  if (namespaceSeparator)
-    b->uri[len - 1] = namespaceSeparator;
-  b->prefix = prefix;
-  b->attId = attId;
-  b->prevPrefixBinding = prefix->binding;
-  /* NULL binding when default namespace undeclared */
-  if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix)
-    prefix->binding = NULL;
-  else
-    prefix->binding = b;
-  b->nextTagBinding = *bindingsPtr;
-  *bindingsPtr = b;
-  /* if attId == NULL then we are not starting a namespace scope */
-  if (attId && startNamespaceDeclHandler)
-    startNamespaceDeclHandler(handlerArg, prefix->name,
-                              prefix->binding ? uri : 0);
-  return XML_ERROR_NONE;
-}
-
-/* The idea here is to avoid using stack for each CDATA section when
-   the whole file is parsed with one call.
-*/
-static enum XML_Error PTRCALL
-cdataSectionProcessor(XML_Parser parser,
-                      const char *start,
-                      const char *end,
-                      const char **endPtr)
-{
-  enum XML_Error result = doCdataSection(parser, encoding, &start, end,
-                                         endPtr, (XML_Bool)!ps_finalBuffer);
-  if (result != XML_ERROR_NONE)
-    return result;
-  if (start) {
-    if (parentParser) {  /* we are parsing an external entity */
-      processor = externalEntityContentProcessor;
-      return externalEntityContentProcessor(parser, start, end, endPtr);
-    }
-    else {
-      processor = contentProcessor;
-      return contentProcessor(parser, start, end, endPtr);
-    }
-  }
-  return result;
-}
-
-/* startPtr gets set to non-null if the section is closed, and to null if
-   the section is not yet closed.
-*/
-static enum XML_Error
-doCdataSection(XML_Parser parser,
-               const ENCODING *enc,
-               const char **startPtr,
-               const char *end,
-               const char **nextPtr,
-               XML_Bool haveMore)
-{
-  const char *s = *startPtr;
-  const char **eventPP;
-  const char **eventEndPP;
-  if (enc == encoding) {
-    eventPP = &eventPtr;
-    *eventPP = s;
-    eventEndPP = &eventEndPtr;
-  }
-  else {
-    eventPP = &(openInternalEntities->internalEventPtr);
-    eventEndPP = &(openInternalEntities->internalEventEndPtr);
-  }
-  *eventPP = s;
-  *startPtr = NULL;
-
-  for (;;) {
-    const char *next;
-    int tok = XmlCdataSectionTok(enc, s, end, &next);
-    *eventEndPP = next;
-    switch (tok) {
-    case XML_TOK_CDATA_SECT_CLOSE:
-      if (endCdataSectionHandler)
-        endCdataSectionHandler(handlerArg);
-#if 0
-      /* see comment under XML_TOK_CDATA_SECT_OPEN */
-      else if (characterDataHandler)
-        characterDataHandler(handlerArg, dataBuf, 0);
-#endif
-      else if (defaultHandler)
-        reportDefault(parser, enc, s, next);
-      *startPtr = next;
-      *nextPtr = next;
-      if (ps_parsing == XML_FINISHED)
-        return XML_ERROR_ABORTED;
-      else
-        return XML_ERROR_NONE;
-    case XML_TOK_DATA_NEWLINE:
-      if (characterDataHandler) {
-        XML_Char c = 0xA;
-        characterDataHandler(handlerArg, &c, 1);
-      }
-      else if (defaultHandler)
-        reportDefault(parser, enc, s, next);
-      break;
-    case XML_TOK_DATA_CHARS:
-      {
-        XML_CharacterDataHandler charDataHandler = characterDataHandler;
-        if (charDataHandler) {
-          if (MUST_CONVERT(enc, s)) {
-            for (;;) {
-              ICHAR *dataPtr = (ICHAR *)dataBuf;
-              const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
-              *eventEndPP = next;
-              charDataHandler(handlerArg, dataBuf,
-                              (int)(dataPtr - (ICHAR *)dataBuf));
-              if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
-                break;
-              *eventPP = s;
-            }
-          }
-          else
-            charDataHandler(handlerArg,
-                            (XML_Char *)s,
-                            (int)((XML_Char *)next - (XML_Char *)s));
-        }
-        else if (defaultHandler)
-          reportDefault(parser, enc, s, next);
-      }
-      break;
-    case XML_TOK_INVALID:
-      *eventPP = next;
-      return XML_ERROR_INVALID_TOKEN;
-    case XML_TOK_PARTIAL_CHAR:
-      if (haveMore) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      return XML_ERROR_PARTIAL_CHAR;
-    case XML_TOK_PARTIAL:
-    case XML_TOK_NONE:
-      if (haveMore) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      return XML_ERROR_UNCLOSED_CDATA_SECTION;
-    default:
-      *eventPP = next;
-      return XML_ERROR_UNEXPECTED_STATE;
-    }
-
-    *eventPP = s = next;
-    switch (ps_parsing) {
-    case XML_SUSPENDED:
-      *nextPtr = next;
-      return XML_ERROR_NONE;
-    case XML_FINISHED:
-      return XML_ERROR_ABORTED;
-    default: ;
-    }
-  }
-  /* not reached */
-}
-
-#ifdef XML_DTD
-
-/* The idea here is to avoid using stack for each IGNORE section when
-   the whole file is parsed with one call.
-*/
-static enum XML_Error PTRCALL
-ignoreSectionProcessor(XML_Parser parser,
-                       const char *start,
-                       const char *end,
-                       const char **endPtr)
-{
-  enum XML_Error result = doIgnoreSection(parser, encoding, &start, end,
-                                          endPtr, (XML_Bool)!ps_finalBuffer);
-  if (result != XML_ERROR_NONE)
-    return result;
-  if (start) {
-    processor = prologProcessor;
-    return prologProcessor(parser, start, end, endPtr);
-  }
-  return result;
-}
-
-/* startPtr gets set to non-null is the section is closed, and to null
-   if the section is not yet closed.
-*/
-static enum XML_Error
-doIgnoreSection(XML_Parser parser,
-                const ENCODING *enc,
-                const char **startPtr,
-                const char *end,
-                const char **nextPtr,
-                XML_Bool haveMore)
-{
-  const char *next;
-  int tok;
-  const char *s = *startPtr;
-  const char **eventPP;
-  const char **eventEndPP;
-  if (enc == encoding) {
-    eventPP = &eventPtr;
-    *eventPP = s;
-    eventEndPP = &eventEndPtr;
-  }
-  else {
-    eventPP = &(openInternalEntities->internalEventPtr);
-    eventEndPP = &(openInternalEntities->internalEventEndPtr);
-  }
-  *eventPP = s;
-  *startPtr = NULL;
-  tok = XmlIgnoreSectionTok(enc, s, end, &next);
-  *eventEndPP = next;
-  switch (tok) {
-  case XML_TOK_IGNORE_SECT:
-    if (defaultHandler)
-      reportDefault(parser, enc, s, next);
-    *startPtr = next;
-    *nextPtr = next;
-    if (ps_parsing == XML_FINISHED)
-      return XML_ERROR_ABORTED;
-    else
-      return XML_ERROR_NONE;
-  case XML_TOK_INVALID:
-    *eventPP = next;
-    return XML_ERROR_INVALID_TOKEN;
-  case XML_TOK_PARTIAL_CHAR:
-    if (haveMore) {
-      *nextPtr = s;
-      return XML_ERROR_NONE;
-    }
-    return XML_ERROR_PARTIAL_CHAR;
-  case XML_TOK_PARTIAL:
-  case XML_TOK_NONE:
-    if (haveMore) {
-      *nextPtr = s;
-      return XML_ERROR_NONE;
-    }
-    return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */
-  default:
-    *eventPP = next;
-    return XML_ERROR_UNEXPECTED_STATE;
-  }
-  /* not reached */
-}
-
-#endif /* XML_DTD */
-
-static enum XML_Error
-initializeEncoding(XML_Parser parser)
-{
-  const char *s;
-#ifdef XML_UNICODE
-  char encodingBuf[128];
-  if (!protocolEncodingName)
-    s = NULL;
-  else {
-    int i;
-    for (i = 0; protocolEncodingName[i]; i++) {
-      if (i == sizeof(encodingBuf) - 1
-          || (protocolEncodingName[i] & ~0x7f) != 0) {
-        encodingBuf[0] = '\0';
-        break;
-      }
-      encodingBuf[i] = (char)protocolEncodingName[i];
-    }
-    encodingBuf[i] = '\0';
-    s = encodingBuf;
-  }
-#else
-  s = protocolEncodingName;
-#endif
-  if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
-    return XML_ERROR_NONE;
-  return handleUnknownEncoding(parser, protocolEncodingName);
-}
-
-static enum XML_Error
-processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
-               const char *s, const char *next)
-{
-  const char *encodingName = NULL;
-  const XML_Char *storedEncName = NULL;
-  const ENCODING *newEncoding = NULL;
-  const char *version = NULL;
-  const char *versionend;
-  const XML_Char *storedversion = NULL;
-  int standalone = -1;
-  if (!(ns
-        ? XmlParseXmlDeclNS
-        : XmlParseXmlDecl)(isGeneralTextEntity,
-                           encoding,
-                           s,
-                           next,
-                           &eventPtr,
-                           &version,
-                           &versionend,
-                           &encodingName,
-                           &newEncoding,
-                           &standalone)) {
-    if (isGeneralTextEntity)
-      return XML_ERROR_TEXT_DECL;
-    else
-      return XML_ERROR_XML_DECL;
-  }
-  if (!isGeneralTextEntity && standalone == 1) {
-    _dtd->standalone = XML_TRUE;
-#ifdef XML_DTD
-    if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
-      paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
-#endif /* XML_DTD */
-  }
-  if (xmlDeclHandler) {
-    if (encodingName != NULL) {
-      storedEncName = poolStoreString(&temp2Pool,
-                                      encoding,
-                                      encodingName,
-                                      encodingName
-                                      + XmlNameLength(encoding, encodingName));
-      if (!storedEncName)
-              return XML_ERROR_NO_MEMORY;
-      poolFinish(&temp2Pool);
-    }
-    if (version) {
-      storedversion = poolStoreString(&temp2Pool,
-                                      encoding,
-                                      version,
-                                      versionend - encoding->minBytesPerChar);
-      if (!storedversion)
-        return XML_ERROR_NO_MEMORY;
-    }
-    xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
-  }
-  else if (defaultHandler)
-    reportDefault(parser, encoding, s, next);
-  if (protocolEncodingName == NULL) {
-    if (newEncoding) {
-      if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) {
-        eventPtr = encodingName;
-        return XML_ERROR_INCORRECT_ENCODING;
-      }
-      encoding = newEncoding;
-    }
-    else if (encodingName) {
-      enum XML_Error result;
-      if (!storedEncName) {
-        storedEncName = poolStoreString(
-          &temp2Pool, encoding, encodingName,
-          encodingName + XmlNameLength(encoding, encodingName));
-        if (!storedEncName)
-          return XML_ERROR_NO_MEMORY;
-      }
-      result = handleUnknownEncoding(parser, storedEncName);
-      poolClear(&temp2Pool);
-      if (result == XML_ERROR_UNKNOWN_ENCODING)
-        eventPtr = encodingName;
-      return result;
-    }
-  }
-
-  if (storedEncName || storedversion)
-    poolClear(&temp2Pool);
-
-  return XML_ERROR_NONE;
-}
-
-static enum XML_Error
-handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
-{
-  if (unknownEncodingHandler) {
-    XML_Encoding info;
-    int i;
-    for (i = 0; i < 256; i++)
-      info.map[i] = -1;
-    info.convert = NULL;
-    info.data = NULL;
-    info.release = NULL;
-    if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName,
-                               &info)) {
-      ENCODING *enc;
-      unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
-      if (!unknownEncodingMem) {
-        if (info.release)
-          info.release(info.data);
-        return XML_ERROR_NO_MEMORY;
-      }
-      enc = (ns
-             ? XmlInitUnknownEncodingNS
-             : XmlInitUnknownEncoding)(unknownEncodingMem,
-                                       info.map,
-                                       info.convert,
-                                       info.data);
-      if (enc) {
-        unknownEncodingData = info.data;
-        unknownEncodingRelease = info.release;
-        encoding = enc;
-        return XML_ERROR_NONE;
-      }
-    }
-    if (info.release != NULL)
-      info.release(info.data);
-  }
-  return XML_ERROR_UNKNOWN_ENCODING;
-}
-
-static enum XML_Error PTRCALL
-prologInitProcessor(XML_Parser parser,
-                    const char *s,
-                    const char *end,
-                    const char **nextPtr)
-{
-  enum XML_Error result = initializeEncoding(parser);
-  if (result != XML_ERROR_NONE)
-    return result;
-  processor = prologProcessor;
-  return prologProcessor(parser, s, end, nextPtr);
-}
-
-#ifdef XML_DTD
-
-static enum XML_Error PTRCALL
-externalParEntInitProcessor(XML_Parser parser,
-                            const char *s,
-                            const char *end,
-                            const char **nextPtr)
-{
-  enum XML_Error result = initializeEncoding(parser);
-  if (result != XML_ERROR_NONE)
-    return result;
-
-  /* we know now that XML_Parse(Buffer) has been called,
-     so we consider the external parameter entity read */
-  _dtd->paramEntityRead = XML_TRUE;
-
-  if (prologState.inEntityValue) {
-    processor = entityValueInitProcessor;
-    return entityValueInitProcessor(parser, s, end, nextPtr);
-  }
-  else {
-    processor = externalParEntProcessor;
-    return externalParEntProcessor(parser, s, end, nextPtr);
-  }
-}
-
-static enum XML_Error PTRCALL
-entityValueInitProcessor(XML_Parser parser,
-                         const char *s,
-                         const char *end,
-                         const char **nextPtr)
-{
-  int tok;
-  const char *start = s;
-  const char *next = start;
-  eventPtr = start;
-
-  for (;;) {
-    tok = XmlPrologTok(encoding, start, end, &next);
-    eventEndPtr = next;
-    if (tok <= 0) {
-      if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      switch (tok) {
-      case XML_TOK_INVALID:
-        return XML_ERROR_INVALID_TOKEN;
-      case XML_TOK_PARTIAL:
-        return XML_ERROR_UNCLOSED_TOKEN;
-      case XML_TOK_PARTIAL_CHAR:
-        return XML_ERROR_PARTIAL_CHAR;
-      case XML_TOK_NONE:   /* start == end */
-      default:
-        break;
-      }
-      /* found end of entity value - can store it now */
-      return storeEntityValue(parser, encoding, s, end);
-    }
-    else if (tok == XML_TOK_XML_DECL) {
-      enum XML_Error result;
-      result = processXmlDecl(parser, 0, start, next);
-      if (result != XML_ERROR_NONE)
-        return result;
-      switch (ps_parsing) {
-      case XML_SUSPENDED:
-        *nextPtr = next;
-        return XML_ERROR_NONE;
-      case XML_FINISHED:
-        return XML_ERROR_ABORTED;
-      default:
-        *nextPtr = next;
-      }
-      /* stop scanning for text declaration - we found one */
-      processor = entityValueProcessor;
-      return entityValueProcessor(parser, next, end, nextPtr);
-    }
-    /* If we are at the end of the buffer, this would cause XmlPrologTok to
-       return XML_TOK_NONE on the next call, which would then cause the
-       function to exit with *nextPtr set to s - that is what we want for other
-       tokens, but not for the BOM - we would rather like to skip it;
-       then, when this routine is entered the next time, XmlPrologTok will
-       return XML_TOK_INVALID, since the BOM is still in the buffer
-    */
-    else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) {
-      *nextPtr = next;
-      return XML_ERROR_NONE;
-    }
-    start = next;
-    eventPtr = start;
-  }
-}
-
-static enum XML_Error PTRCALL
-externalParEntProcessor(XML_Parser parser,
-                        const char *s,
-                        const char *end,
-                        const char **nextPtr)
-{
-  const char *next = s;
-  int tok;
-
-  tok = XmlPrologTok(encoding, s, end, &next);
-  if (tok <= 0) {
-    if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
-      *nextPtr = s;
-      return XML_ERROR_NONE;
-    }
-    switch (tok) {
-    case XML_TOK_INVALID:
-      return XML_ERROR_INVALID_TOKEN;
-    case XML_TOK_PARTIAL:
-      return XML_ERROR_UNCLOSED_TOKEN;
-    case XML_TOK_PARTIAL_CHAR:
-      return XML_ERROR_PARTIAL_CHAR;
-    case XML_TOK_NONE:   /* start == end */
-    default:
-      break;
-    }
-  }
-  /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
-     However, when parsing an external subset, doProlog will not accept a BOM
-     as valid, and report a syntax error, so we have to skip the BOM
-  */
-  else if (tok == XML_TOK_BOM) {
-    s = next;
-    tok = XmlPrologTok(encoding, s, end, &next);
-  }
-
-  processor = prologProcessor;
-  return doProlog(parser, encoding, s, end, tok, next,
-                  nextPtr, (XML_Bool)!ps_finalBuffer);
-}
-
-static enum XML_Error PTRCALL
-entityValueProcessor(XML_Parser parser,
-                     const char *s,
-                     const char *end,
-                     const char **nextPtr)
-{
-  const char *start = s;
-  const char *next = s;
-  const ENCODING *enc = encoding;
-  int tok;
-
-  for (;;) {
-    tok = XmlPrologTok(enc, start, end, &next);
-    if (tok <= 0) {
-      if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      switch (tok) {
-      case XML_TOK_INVALID:
-        return XML_ERROR_INVALID_TOKEN;
-      case XML_TOK_PARTIAL:
-        return XML_ERROR_UNCLOSED_TOKEN;
-      case XML_TOK_PARTIAL_CHAR:
-        return XML_ERROR_PARTIAL_CHAR;
-      case XML_TOK_NONE:   /* start == end */
-      default:
-        break;
-      }
-      /* found end of entity value - can store it now */
-      return storeEntityValue(parser, enc, s, end);
-    }
-    start = next;
-  }
-}
-
-#endif /* XML_DTD */
-
-static enum XML_Error PTRCALL
-prologProcessor(XML_Parser parser,
-                const char *s,
-                const char *end,
-                const char **nextPtr)
-{
-  const char *next = s;
-  int tok = XmlPrologTok(encoding, s, end, &next);
-  return doProlog(parser, encoding, s, end, tok, next,
-                  nextPtr, (XML_Bool)!ps_finalBuffer);
-}
-
-static enum XML_Error
-doProlog(XML_Parser parser,
-         const ENCODING *enc,
-         const char *s,
-         const char *end,
-         int tok,
-         const char *next,
-         const char **nextPtr,
-         XML_Bool haveMore)
-{
-#ifdef XML_DTD
-  static const XML_Char externalSubsetName[] = { ASCII_HASH , '\0' };
-#endif /* XML_DTD */
-  static const XML_Char atypeCDATA[] =
-      { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
-  static const XML_Char atypeID[] = { ASCII_I, ASCII_D, '\0' };
-  static const XML_Char atypeIDREF[] =
-      { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
-  static const XML_Char atypeIDREFS[] =
-      { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
-  static const XML_Char atypeENTITY[] =
-      { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
-  static const XML_Char atypeENTITIES[] = { ASCII_E, ASCII_N,
-      ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' };
-  static const XML_Char atypeNMTOKEN[] = {
-      ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
-  static const XML_Char atypeNMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T,
-      ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' };
-  static const XML_Char notationPrefix[] = { ASCII_N, ASCII_O, ASCII_T,
-      ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0' };
-  static const XML_Char enumValueSep[] = { ASCII_PIPE, '\0' };
-  static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' };
-
-  /* save one level of indirection */
-  DTD * const dtd = _dtd;
-
-  const char **eventPP;
-  const char **eventEndPP;
-  enum XML_Content_Quant quant;
-
-  if (enc == encoding) {
-    eventPP = &eventPtr;
-    eventEndPP = &eventEndPtr;
-  }
-  else {
-    eventPP = &(openInternalEntities->internalEventPtr);
-    eventEndPP = &(openInternalEntities->internalEventEndPtr);
-  }
-
-  for (;;) {
-    int role;
-    XML_Bool handleDefault = XML_TRUE;
-    *eventPP = s;
-    *eventEndPP = next;
-    if (tok <= 0) {
-      if (haveMore && tok != XML_TOK_INVALID) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      switch (tok) {
-      case XML_TOK_INVALID:
-        *eventPP = next;
-        return XML_ERROR_INVALID_TOKEN;
-      case XML_TOK_PARTIAL:
-        return XML_ERROR_UNCLOSED_TOKEN;
-      case XML_TOK_PARTIAL_CHAR:
-        return XML_ERROR_PARTIAL_CHAR;
-      case -XML_TOK_PROLOG_S:
-        tok = -tok;
-        break;
-      case XML_TOK_NONE:
-#ifdef XML_DTD
-        /* for internal PE NOT referenced between declarations */
-        if (enc != encoding && !openInternalEntities->betweenDecl) {
-          *nextPtr = s;
-          return XML_ERROR_NONE;
-        }
-        /* WFC: PE Between Declarations - must check that PE contains
-           complete markup, not only for external PEs, but also for
-           internal PEs if the reference occurs between declarations.
-        */
-        if (isParamEntity || enc != encoding) {
-          if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
-              == XML_ROLE_ERROR)
-            return XML_ERROR_INCOMPLETE_PE;
-          *nextPtr = s;
-          return XML_ERROR_NONE;
-        }
-#endif /* XML_DTD */
-        return XML_ERROR_NO_ELEMENTS;
-      default:
-        tok = -tok;
-        next = end;
-        break;
-      }
-    }
-    role = XmlTokenRole(&prologState, tok, s, next, enc);
-    switch (role) {
-    case XML_ROLE_XML_DECL:
-      {
-        enum XML_Error result = processXmlDecl(parser, 0, s, next);
-        if (result != XML_ERROR_NONE)
-          return result;
-        enc = encoding;
-        handleDefault = XML_FALSE;
-      }
-      break;
-    case XML_ROLE_DOCTYPE_NAME:
-      if (startDoctypeDeclHandler) {
-        doctypeName = poolStoreString(&tempPool, enc, s, next);
-        if (!doctypeName)
-          return XML_ERROR_NO_MEMORY;
-        poolFinish(&tempPool);
-        doctypePubid = NULL;
-        handleDefault = XML_FALSE;
-      }
-      doctypeSysid = NULL; /* always initialize to NULL */
-      break;
-    case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
-      if (startDoctypeDeclHandler) {
-        startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
-                                doctypePubid, 1);
-        doctypeName = NULL;
-        poolClear(&tempPool);
-        handleDefault = XML_FALSE;
-      }
-      break;
-#ifdef XML_DTD
-    case XML_ROLE_TEXT_DECL:
-      {
-        enum XML_Error result = processXmlDecl(parser, 1, s, next);
-        if (result != XML_ERROR_NONE)
-          return result;
-        enc = encoding;
-        handleDefault = XML_FALSE;
-      }
-      break;
-#endif /* XML_DTD */
-    case XML_ROLE_DOCTYPE_PUBLIC_ID:
-#ifdef XML_DTD
-      useForeignDTD = XML_FALSE;
-      declEntity = (ENTITY *)lookup(parser,
-                                    &dtd->paramEntities,
-                                    externalSubsetName,
-                                    sizeof(ENTITY));
-      if (!declEntity)
-        return XML_ERROR_NO_MEMORY;
-#endif /* XML_DTD */
-      dtd->hasParamEntityRefs = XML_TRUE;
-      if (startDoctypeDeclHandler) {
-        XML_Char *pubId;
-        if (!XmlIsPublicId(enc, s, next, eventPP))
-          return XML_ERROR_PUBLICID;
-        pubId = poolStoreString(&tempPool, enc,
-                                s + enc->minBytesPerChar,
-                                next - enc->minBytesPerChar);
-        if (!pubId)
-          return XML_ERROR_NO_MEMORY;
-        normalizePublicId(pubId);
-        poolFinish(&tempPool);
-        doctypePubid = pubId;
-        handleDefault = XML_FALSE;
-        goto alreadyChecked;
-      }
-      /* fall through */
-    case XML_ROLE_ENTITY_PUBLIC_ID:
-      if (!XmlIsPublicId(enc, s, next, eventPP))
-        return XML_ERROR_PUBLICID;
-    alreadyChecked:
-      if (dtd->keepProcessing && declEntity) {
-        XML_Char *tem = poolStoreString(&dtd->pool,
-                                        enc,
-                                        s + enc->minBytesPerChar,
-                                        next - enc->minBytesPerChar);
-        if (!tem)
-          return XML_ERROR_NO_MEMORY;
-        normalizePublicId(tem);
-        declEntity->publicId = tem;
-        poolFinish(&dtd->pool);
-        if (entityDeclHandler)
-          handleDefault = XML_FALSE;
-      }
-      break;
-    case XML_ROLE_DOCTYPE_CLOSE:
-      if (doctypeName) {
-        startDoctypeDeclHandler(handlerArg, doctypeName,
-                                doctypeSysid, doctypePubid, 0);
-        poolClear(&tempPool);
-        handleDefault = XML_FALSE;
-      }
-      /* doctypeSysid will be non-NULL in the case of a previous
-         XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler
-         was not set, indicating an external subset
-      */
-#ifdef XML_DTD
-      if (doctypeSysid || useForeignDTD) {
-        XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
-        dtd->hasParamEntityRefs = XML_TRUE;
-        if (paramEntityParsing && externalEntityRefHandler) {
-          ENTITY *entity = (ENTITY *)lookup(parser,
-                                            &dtd->paramEntities,
-                                            externalSubsetName,
-                                            sizeof(ENTITY));
-          if (!entity)
-            return XML_ERROR_NO_MEMORY;
-          if (useForeignDTD)
-            entity->base = curBase;
-          dtd->paramEntityRead = XML_FALSE;
-          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
-                                        0,
-                                        entity->base,
-                                        entity->systemId,
-                                        entity->publicId))
-            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
-          if (dtd->paramEntityRead) {
-            if (!dtd->standalone &&
-                notStandaloneHandler &&
-                !notStandaloneHandler(handlerArg))
-              return XML_ERROR_NOT_STANDALONE;
-          }
-          /* if we didn't read the foreign DTD then this means that there
-             is no external subset and we must reset dtd->hasParamEntityRefs
-          */
-          else if (!doctypeSysid)
-            dtd->hasParamEntityRefs = hadParamEntityRefs;
-          /* end of DTD - no need to update dtd->keepProcessing */
-        }
-        useForeignDTD = XML_FALSE;
-      }
-#endif /* XML_DTD */
-      if (endDoctypeDeclHandler) {
-        endDoctypeDeclHandler(handlerArg);
-        handleDefault = XML_FALSE;
-      }
-      break;
-    case XML_ROLE_INSTANCE_START:
-#ifdef XML_DTD
-      /* if there is no DOCTYPE declaration then now is the
-         last chance to read the foreign DTD
-      */
-      if (useForeignDTD) {
-        XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
-        dtd->hasParamEntityRefs = XML_TRUE;
-        if (paramEntityParsing && externalEntityRefHandler) {
-          ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
-                                            externalSubsetName,
-                                            sizeof(ENTITY));
-          if (!entity)
-            return XML_ERROR_NO_MEMORY;
-          entity->base = curBase;
-          dtd->paramEntityRead = XML_FALSE;
-          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
-                                        0,
-                                        entity->base,
-                                        entity->systemId,
-                                        entity->publicId))
-            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
-          if (dtd->paramEntityRead) {
-            if (!dtd->standalone &&
-                notStandaloneHandler &&
-                !notStandaloneHandler(handlerArg))
-              return XML_ERROR_NOT_STANDALONE;
-          }
-          /* if we didn't read the foreign DTD then this means that there
-             is no external subset and we must reset dtd->hasParamEntityRefs
-          */
-          else
-            dtd->hasParamEntityRefs = hadParamEntityRefs;
-          /* end of DTD - no need to update dtd->keepProcessing */
-        }
-      }
-#endif /* XML_DTD */
-      processor = contentProcessor;
-      return contentProcessor(parser, s, end, nextPtr);
-    case XML_ROLE_ATTLIST_ELEMENT_NAME:
-      declElementType = getElementType(parser, enc, s, next);
-      if (!declElementType)
-        return XML_ERROR_NO_MEMORY;
-      goto checkAttListDeclHandler;
-    case XML_ROLE_ATTRIBUTE_NAME:
-      declAttributeId = getAttributeId(parser, enc, s, next);
-      if (!declAttributeId)
-        return XML_ERROR_NO_MEMORY;
-      declAttributeIsCdata = XML_FALSE;
-      declAttributeType = NULL;
-      declAttributeIsId = XML_FALSE;
-      goto checkAttListDeclHandler;
-    case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
-      declAttributeIsCdata = XML_TRUE;
-      declAttributeType = atypeCDATA;
-      goto checkAttListDeclHandler;
-    case XML_ROLE_ATTRIBUTE_TYPE_ID:
-      declAttributeIsId = XML_TRUE;
-      declAttributeType = atypeID;
-      goto checkAttListDeclHandler;
-    case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
-      declAttributeType = atypeIDREF;
-      goto checkAttListDeclHandler;
-    case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
-      declAttributeType = atypeIDREFS;
-      goto checkAttListDeclHandler;
-    case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
-      declAttributeType = atypeENTITY;
-      goto checkAttListDeclHandler;
-    case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
-      declAttributeType = atypeENTITIES;
-      goto checkAttListDeclHandler;
-    case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
-      declAttributeType = atypeNMTOKEN;
-      goto checkAttListDeclHandler;
-    case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
-      declAttributeType = atypeNMTOKENS;
-    checkAttListDeclHandler:
-      if (dtd->keepProcessing && attlistDeclHandler)
-        handleDefault = XML_FALSE;
-      break;
-    case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
-    case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
-      if (dtd->keepProcessing && attlistDeclHandler) {
-        const XML_Char *prefix;
-        if (declAttributeType) {
-          prefix = enumValueSep;
-        }
-        else {
-          prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE
-                    ? notationPrefix
-                    : enumValueStart);
-        }
-        if (!poolAppendString(&tempPool, prefix))
-          return XML_ERROR_NO_MEMORY;
-        if (!poolAppend(&tempPool, enc, s, next))
-          return XML_ERROR_NO_MEMORY;
-        declAttributeType = tempPool.start;
-        handleDefault = XML_FALSE;
-      }
-      break;
-    case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
-    case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
-      if (dtd->keepProcessing) {
-        if (!defineAttribute(declElementType, declAttributeId,
-                             declAttributeIsCdata, declAttributeIsId,
-                             0, parser))
-          return XML_ERROR_NO_MEMORY;
-        if (attlistDeclHandler && declAttributeType) {
-          if (*declAttributeType == XML_T(ASCII_LPAREN)
-              || (*declAttributeType == XML_T(ASCII_N)
-                  && declAttributeType[1] == XML_T(ASCII_O))) {
-            /* Enumerated or Notation type */
-            if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
-                || !poolAppendChar(&tempPool, XML_T('\0')))
-              return XML_ERROR_NO_MEMORY;
-            declAttributeType = tempPool.start;
-            poolFinish(&tempPool);
-          }
-          *eventEndPP = s;
-          attlistDeclHandler(handlerArg, declElementType->name,
-                             declAttributeId->name, declAttributeType,
-                             0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
-          poolClear(&tempPool);
-          handleDefault = XML_FALSE;
-        }
-      }
-      break;
-    case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
-    case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
-      if (dtd->keepProcessing) {
-        const XML_Char *attVal;
-        enum XML_Error result =
-          storeAttributeValue(parser, enc, declAttributeIsCdata,
-                              s + enc->minBytesPerChar,
-                              next - enc->minBytesPerChar,
-                              &dtd->pool);
-        if (result)
-          return result;
-        attVal = poolStart(&dtd->pool);
-        poolFinish(&dtd->pool);
-        /* ID attributes aren't allowed to have a default */
-        if (!defineAttribute(declElementType, declAttributeId,
-                             declAttributeIsCdata, XML_FALSE, attVal, parser))
-          return XML_ERROR_NO_MEMORY;
-        if (attlistDeclHandler && declAttributeType) {
-          if (*declAttributeType == XML_T(ASCII_LPAREN)
-              || (*declAttributeType == XML_T(ASCII_N)
-                  && declAttributeType[1] == XML_T(ASCII_O))) {
-            /* Enumerated or Notation type */
-            if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
-                || !poolAppendChar(&tempPool, XML_T('\0')))
-              return XML_ERROR_NO_MEMORY;
-            declAttributeType = tempPool.start;
-            poolFinish(&tempPool);
-          }
-          *eventEndPP = s;
-          attlistDeclHandler(handlerArg, declElementType->name,
-                             declAttributeId->name, declAttributeType,
-                             attVal,
-                             role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
-          poolClear(&tempPool);
-          handleDefault = XML_FALSE;
-        }
-      }
-      break;
-    case XML_ROLE_ENTITY_VALUE:
-      if (dtd->keepProcessing) {
-        enum XML_Error result = storeEntityValue(parser, enc,
-                                            s + enc->minBytesPerChar,
-                                            next - enc->minBytesPerChar);
-        if (declEntity) {
-          declEntity->textPtr = poolStart(&dtd->entityValuePool);
-          declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
-          poolFinish(&dtd->entityValuePool);
-          if (entityDeclHandler) {
-            *eventEndPP = s;
-            entityDeclHandler(handlerArg,
-                              declEntity->name,
-                              declEntity->is_param,
-                              declEntity->textPtr,
-                              declEntity->textLen,
-                              curBase, 0, 0, 0);
-            handleDefault = XML_FALSE;
-          }
-        }
-        else
-          poolDiscard(&dtd->entityValuePool);
-        if (result != XML_ERROR_NONE)
-          return result;
-      }
-      break;
-    case XML_ROLE_DOCTYPE_SYSTEM_ID:
-#ifdef XML_DTD
-      useForeignDTD = XML_FALSE;
-#endif /* XML_DTD */
-      dtd->hasParamEntityRefs = XML_TRUE;
-      if (startDoctypeDeclHandler) {
-        doctypeSysid = poolStoreString(&tempPool, enc,
-                                       s + enc->minBytesPerChar,
-                                       next - enc->minBytesPerChar);
-        if (doctypeSysid == NULL)
-          return XML_ERROR_NO_MEMORY;
-        poolFinish(&tempPool);
-        handleDefault = XML_FALSE;
-      }
-#ifdef XML_DTD
-      else
-        /* use externalSubsetName to make doctypeSysid non-NULL
-           for the case where no startDoctypeDeclHandler is set */
-        doctypeSysid = externalSubsetName;
-#endif /* XML_DTD */
-      if (!dtd->standalone
-#ifdef XML_DTD
-          && !paramEntityParsing
-#endif /* XML_DTD */
-          && notStandaloneHandler
-          && !notStandaloneHandler(handlerArg))
-        return XML_ERROR_NOT_STANDALONE;
-#ifndef XML_DTD
-      break;
-#else /* XML_DTD */
-      if (!declEntity) {
-        declEntity = (ENTITY *)lookup(parser,
-                                      &dtd->paramEntities,
-                                      externalSubsetName,
-                                      sizeof(ENTITY));
-        if (!declEntity)
-          return XML_ERROR_NO_MEMORY;
-        declEntity->publicId = NULL;
-      }
-#endif /* XML_DTD */
-      /* falls through */
-    case XML_ROLE_ENTITY_SYSTEM_ID:
-      if (dtd->keepProcessing && declEntity) {
-        declEntity->systemId = poolStoreString(&dtd->pool, enc,
-                                               s + enc->minBytesPerChar,
-                                               next - enc->minBytesPerChar);
-        if (!declEntity->systemId)
-          return XML_ERROR_NO_MEMORY;
-        declEntity->base = curBase;
-        poolFinish(&dtd->pool);
-        if (entityDeclHandler)
-          handleDefault = XML_FALSE;
-      }
-      break;
-    case XML_ROLE_ENTITY_COMPLETE:
-      if (dtd->keepProcessing && declEntity && entityDeclHandler) {
-        *eventEndPP = s;
-        entityDeclHandler(handlerArg,
-                          declEntity->name,
-                          declEntity->is_param,
-                          0,0,
-                          declEntity->base,
-                          declEntity->systemId,
-                          declEntity->publicId,
-                          0);
-        handleDefault = XML_FALSE;
-      }
-      break;
-    case XML_ROLE_ENTITY_NOTATION_NAME:
-      if (dtd->keepProcessing && declEntity) {
-        declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
-        if (!declEntity->notation)
-          return XML_ERROR_NO_MEMORY;
-        poolFinish(&dtd->pool);
-        if (unparsedEntityDeclHandler) {
-          *eventEndPP = s;
-          unparsedEntityDeclHandler(handlerArg,
-                                    declEntity->name,
-                                    declEntity->base,
-                                    declEntity->systemId,
-                                    declEntity->publicId,
-                                    declEntity->notation);
-          handleDefault = XML_FALSE;
-        }
-        else if (entityDeclHandler) {
-          *eventEndPP = s;
-          entityDeclHandler(handlerArg,
-                            declEntity->name,
-                            0,0,0,
-                            declEntity->base,
-                            declEntity->systemId,
-                            declEntity->publicId,
-                            declEntity->notation);
-          handleDefault = XML_FALSE;
-        }
-      }
-      break;
-    case XML_ROLE_GENERAL_ENTITY_NAME:
-      {
-        if (XmlPredefinedEntityName(enc, s, next)) {
-          declEntity = NULL;
-          break;
-        }
-        if (dtd->keepProcessing) {
-          const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
-          if (!name)
-            return XML_ERROR_NO_MEMORY;
-          declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
-                                        sizeof(ENTITY));
-          if (!declEntity)
-            return XML_ERROR_NO_MEMORY;
-          if (declEntity->name != name) {
-            poolDiscard(&dtd->pool);
-            declEntity = NULL;
-          }
-          else {
-            poolFinish(&dtd->pool);
-            declEntity->publicId = NULL;
-            declEntity->is_param = XML_FALSE;
-            /* if we have a parent parser or are reading an internal parameter
-               entity, then the entity declaration is not considered "internal"
-            */
-            declEntity->is_internal = !(parentParser || openInternalEntities);
-            if (entityDeclHandler)
-              handleDefault = XML_FALSE;
-          }
-        }
-        else {
-          poolDiscard(&dtd->pool);
-          declEntity = NULL;
-        }
-      }
-      break;
-    case XML_ROLE_PARAM_ENTITY_NAME:
-#ifdef XML_DTD
-      if (dtd->keepProcessing) {
-        const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
-        if (!name)
-          return XML_ERROR_NO_MEMORY;
-        declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
-                                           name, sizeof(ENTITY));
-        if (!declEntity)
-          return XML_ERROR_NO_MEMORY;
-        if (declEntity->name != name) {
-          poolDiscard(&dtd->pool);
-          declEntity = NULL;
-        }
-        else {
-          poolFinish(&dtd->pool);
-          declEntity->publicId = NULL;
-          declEntity->is_param = XML_TRUE;
-          /* if we have a parent parser or are reading an internal parameter
-             entity, then the entity declaration is not considered "internal"
-          */
-          declEntity->is_internal = !(parentParser || openInternalEntities);
-          if (entityDeclHandler)
-            handleDefault = XML_FALSE;
-        }
-      }
-      else {
-        poolDiscard(&dtd->pool);
-        declEntity = NULL;
-      }
-#else /* not XML_DTD */
-      declEntity = NULL;
-#endif /* XML_DTD */
-      break;
-    case XML_ROLE_NOTATION_NAME:
-      declNotationPublicId = NULL;
-      declNotationName = NULL;
-      if (notationDeclHandler) {
-        declNotationName = poolStoreString(&tempPool, enc, s, next);
-        if (!declNotationName)
-          return XML_ERROR_NO_MEMORY;
-        poolFinish(&tempPool);
-        handleDefault = XML_FALSE;
-      }
-      break;
-    case XML_ROLE_NOTATION_PUBLIC_ID:
-      if (!XmlIsPublicId(enc, s, next, eventPP))
-        return XML_ERROR_PUBLICID;
-      if (declNotationName) {  /* means notationDeclHandler != NULL */
-        XML_Char *tem = poolStoreString(&tempPool,
-                                        enc,
-                                        s + enc->minBytesPerChar,
-                                        next - enc->minBytesPerChar);
-        if (!tem)
-          return XML_ERROR_NO_MEMORY;
-        normalizePublicId(tem);
-        declNotationPublicId = tem;
-        poolFinish(&tempPool);
-        handleDefault = XML_FALSE;
-      }
-      break;
-    case XML_ROLE_NOTATION_SYSTEM_ID:
-      if (declNotationName && notationDeclHandler) {
-        const XML_Char *systemId
-          = poolStoreString(&tempPool, enc,
-                            s + enc->minBytesPerChar,
-                            next - enc->minBytesPerChar);
-        if (!systemId)
-          return XML_ERROR_NO_MEMORY;
-        *eventEndPP = s;
-        notationDeclHandler(handlerArg,
-                            declNotationName,
-                            curBase,
-                            systemId,
-                            declNotationPublicId);
-        handleDefault = XML_FALSE;
-      }
-      poolClear(&tempPool);
-      break;
-    case XML_ROLE_NOTATION_NO_SYSTEM_ID:
-      if (declNotationPublicId && notationDeclHandler) {
-        *eventEndPP = s;
-        notationDeclHandler(handlerArg,
-                            declNotationName,
-                            curBase,
-                            0,
-                            declNotationPublicId);
-        handleDefault = XML_FALSE;
-      }
-      poolClear(&tempPool);
-      break;
-    case XML_ROLE_ERROR:
-      switch (tok) {
-      case XML_TOK_PARAM_ENTITY_REF:
-        /* PE references in internal subset are
-           not allowed within declarations. */
-        return XML_ERROR_PARAM_ENTITY_REF;
-      case XML_TOK_XML_DECL:
-        return XML_ERROR_MISPLACED_XML_PI;
-      default:
-        return XML_ERROR_SYNTAX;
-      }
-#ifdef XML_DTD
-    case XML_ROLE_IGNORE_SECT:
-      {
-        enum XML_Error result;
-        if (defaultHandler)
-          reportDefault(parser, enc, s, next);
-        handleDefault = XML_FALSE;
-        result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
-        if (result != XML_ERROR_NONE)
-          return result;
-        else if (!next) {
-          processor = ignoreSectionProcessor;
-          return result;
-        }
-      }
-      break;
-#endif /* XML_DTD */
-    case XML_ROLE_GROUP_OPEN:
-      if (prologState.level >= groupSize) {
-        if (groupSize) {
-          char *temp = (char *)REALLOC(groupConnector, groupSize *= 2);
-          if (temp == NULL)
-            return XML_ERROR_NO_MEMORY;
-          groupConnector = temp;
-          if (dtd->scaffIndex) {
-            int *temp = (int *)REALLOC(dtd->scaffIndex,
-                          groupSize * sizeof(int));
-            if (temp == NULL)
-              return XML_ERROR_NO_MEMORY;
-            dtd->scaffIndex = temp;
-          }
-        }
-        else {
-          groupConnector = (char *)MALLOC(groupSize = 32);
-          if (!groupConnector)
-            return XML_ERROR_NO_MEMORY;
-        }
-      }
-      groupConnector[prologState.level] = 0;
-      if (dtd->in_eldecl) {
-        int myindex = nextScaffoldPart(parser);
-        if (myindex < 0)
-          return XML_ERROR_NO_MEMORY;
-        dtd->scaffIndex[dtd->scaffLevel] = myindex;
-        dtd->scaffLevel++;
-        dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
-        if (elementDeclHandler)
-          handleDefault = XML_FALSE;
-      }
-      break;
-    case XML_ROLE_GROUP_SEQUENCE:
-      if (groupConnector[prologState.level] == ASCII_PIPE)
-        return XML_ERROR_SYNTAX;
-      groupConnector[prologState.level] = ASCII_COMMA;
-      if (dtd->in_eldecl && elementDeclHandler)
-        handleDefault = XML_FALSE;
-      break;
-    case XML_ROLE_GROUP_CHOICE:
-      if (groupConnector[prologState.level] == ASCII_COMMA)
-        return XML_ERROR_SYNTAX;
-      if (dtd->in_eldecl
-          && !groupConnector[prologState.level]
-          && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
-              != XML_CTYPE_MIXED)
-          ) {
-        dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
-            = XML_CTYPE_CHOICE;
-        if (elementDeclHandler)
-          handleDefault = XML_FALSE;
-      }
-      groupConnector[prologState.level] = ASCII_PIPE;
-      break;
-    case XML_ROLE_PARAM_ENTITY_REF:
-#ifdef XML_DTD
-    case XML_ROLE_INNER_PARAM_ENTITY_REF:
-      dtd->hasParamEntityRefs = XML_TRUE;
-      if (!paramEntityParsing)
-        dtd->keepProcessing = dtd->standalone;
-      else {
-        const XML_Char *name;
-        ENTITY *entity;
-        name = poolStoreString(&dtd->pool, enc,
-                                s + enc->minBytesPerChar,
-                                next - enc->minBytesPerChar);
-        if (!name)
-          return XML_ERROR_NO_MEMORY;
-        entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
-        poolDiscard(&dtd->pool);
-        /* first, determine if a check for an existing declaration is needed;
-           if yes, check that the entity exists, and that it is internal,
-           otherwise call the skipped entity handler
-        */
-        if (prologState.documentEntity &&
-            (dtd->standalone
-             ? !openInternalEntities
-             : !dtd->hasParamEntityRefs)) {
-          if (!entity)
-            return XML_ERROR_UNDEFINED_ENTITY;
-          else if (!entity->is_internal)
-            return XML_ERROR_ENTITY_DECLARED_IN_PE;
-        }
-        else if (!entity) {
-          dtd->keepProcessing = dtd->standalone;
-          /* cannot report skipped entities in declarations */
-          if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) {
-            skippedEntityHandler(handlerArg, name, 1);
-            handleDefault = XML_FALSE;
-          }
-          break;
-        }
-        if (entity->open)
-          return XML_ERROR_RECURSIVE_ENTITY_REF;
-        if (entity->textPtr) {
-          enum XML_Error result;
-          XML_Bool betweenDecl =
-            (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
-          result = processInternalEntity(parser, entity, betweenDecl);
-          if (result != XML_ERROR_NONE)
-            return result;
-          handleDefault = XML_FALSE;
-          break;
-        }
-        if (externalEntityRefHandler) {
-          dtd->paramEntityRead = XML_FALSE;
-          entity->open = XML_TRUE;
-          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
-                                        0,
-                                        entity->base,
-                                        entity->systemId,
-                                        entity->publicId)) {
-            entity->open = XML_FALSE;
-            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
-          }
-          entity->open = XML_FALSE;
-          handleDefault = XML_FALSE;
-          if (!dtd->paramEntityRead) {
-            dtd->keepProcessing = dtd->standalone;
-            break;
-          }
-        }
-        else {
-          dtd->keepProcessing = dtd->standalone;
-          break;
-        }
-      }
-#endif /* XML_DTD */
-      if (!dtd->standalone &&
-          notStandaloneHandler &&
-          !notStandaloneHandler(handlerArg))
-        return XML_ERROR_NOT_STANDALONE;
-      break;
-
-    /* Element declaration stuff */
-
-    case XML_ROLE_ELEMENT_NAME:
-      if (elementDeclHandler) {
-        declElementType = getElementType(parser, enc, s, next);
-        if (!declElementType)
-          return XML_ERROR_NO_MEMORY;
-        dtd->scaffLevel = 0;
-        dtd->scaffCount = 0;
-        dtd->in_eldecl = XML_TRUE;
-        handleDefault = XML_FALSE;
-      }
-      break;
-
-    case XML_ROLE_CONTENT_ANY:
-    case XML_ROLE_CONTENT_EMPTY:
-      if (dtd->in_eldecl) {
-        if (elementDeclHandler) {
-          XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content));
-          if (!content)
-            return XML_ERROR_NO_MEMORY;
-          content->quant = XML_CQUANT_NONE;
-          content->name = NULL;
-          content->numchildren = 0;
-          content->children = NULL;
-          content->type = ((role == XML_ROLE_CONTENT_ANY) ?
-                           XML_CTYPE_ANY :
-                           XML_CTYPE_EMPTY);
-          *eventEndPP = s;
-          elementDeclHandler(handlerArg, declElementType->name, content);
-          handleDefault = XML_FALSE;
-        }
-        dtd->in_eldecl = XML_FALSE;
-      }
-      break;
-
-    case XML_ROLE_CONTENT_PCDATA:
-      if (dtd->in_eldecl) {
-        dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
-            = XML_CTYPE_MIXED;
-        if (elementDeclHandler)
-          handleDefault = XML_FALSE;
-      }
-      break;
-
-    case XML_ROLE_CONTENT_ELEMENT:
-      quant = XML_CQUANT_NONE;
-      goto elementContent;
-    case XML_ROLE_CONTENT_ELEMENT_OPT:
-      quant = XML_CQUANT_OPT;
-      goto elementContent;
-    case XML_ROLE_CONTENT_ELEMENT_REP:
-      quant = XML_CQUANT_REP;
-      goto elementContent;
-    case XML_ROLE_CONTENT_ELEMENT_PLUS:
-      quant = XML_CQUANT_PLUS;
-    elementContent:
-      if (dtd->in_eldecl) {
-        ELEMENT_TYPE *el;
-        const XML_Char *name;
-        int nameLen;
-        const char *nxt = (quant == XML_CQUANT_NONE
-                           ? next
-                           : next - enc->minBytesPerChar);
-        int myindex = nextScaffoldPart(parser);
-        if (myindex < 0)
-          return XML_ERROR_NO_MEMORY;
-        dtd->scaffold[myindex].type = XML_CTYPE_NAME;
-        dtd->scaffold[myindex].quant = quant;
-        el = getElementType(parser, enc, s, nxt);
-        if (!el)
-          return XML_ERROR_NO_MEMORY;
-        name = el->name;
-        dtd->scaffold[myindex].name = name;
-        nameLen = 0;
-        for (; name[nameLen++]; );
-        dtd->contentStringLen +=  nameLen;
-        if (elementDeclHandler)
-          handleDefault = XML_FALSE;
-      }
-      break;
-
-    case XML_ROLE_GROUP_CLOSE:
-      quant = XML_CQUANT_NONE;
-      goto closeGroup;
-    case XML_ROLE_GROUP_CLOSE_OPT:
-      quant = XML_CQUANT_OPT;
-      goto closeGroup;
-    case XML_ROLE_GROUP_CLOSE_REP:
-      quant = XML_CQUANT_REP;
-      goto closeGroup;
-    case XML_ROLE_GROUP_CLOSE_PLUS:
-      quant = XML_CQUANT_PLUS;
-    closeGroup:
-      if (dtd->in_eldecl) {
-        if (elementDeclHandler)
-          handleDefault = XML_FALSE;
-        dtd->scaffLevel--;
-        dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant;
-        if (dtd->scaffLevel == 0) {
-          if (!handleDefault) {
-            XML_Content *model = build_model(parser);
-            if (!model)
-              return XML_ERROR_NO_MEMORY;
-            *eventEndPP = s;
-            elementDeclHandler(handlerArg, declElementType->name, model);
-          }
-          dtd->in_eldecl = XML_FALSE;
-          dtd->contentStringLen = 0;
-        }
-      }
-      break;
-      /* End element declaration stuff */
-
-    case XML_ROLE_PI:
-      if (!reportProcessingInstruction(parser, enc, s, next))
-        return XML_ERROR_NO_MEMORY;
-      handleDefault = XML_FALSE;
-      break;
-    case XML_ROLE_COMMENT:
-      if (!reportComment(parser, enc, s, next))
-        return XML_ERROR_NO_MEMORY;
-      handleDefault = XML_FALSE;
-      break;
-    case XML_ROLE_NONE:
-      switch (tok) {
-      case XML_TOK_BOM:
-        handleDefault = XML_FALSE;
-        break;
-      }
-      break;
-    case XML_ROLE_DOCTYPE_NONE:
-      if (startDoctypeDeclHandler)
-        handleDefault = XML_FALSE;
-      break;
-    case XML_ROLE_ENTITY_NONE:
-      if (dtd->keepProcessing && entityDeclHandler)
-        handleDefault = XML_FALSE;
-      break;
-    case XML_ROLE_NOTATION_NONE:
-      if (notationDeclHandler)
-        handleDefault = XML_FALSE;
-      break;
-    case XML_ROLE_ATTLIST_NONE:
-      if (dtd->keepProcessing && attlistDeclHandler)
-        handleDefault = XML_FALSE;
-      break;
-    case XML_ROLE_ELEMENT_NONE:
-      if (elementDeclHandler)
-        handleDefault = XML_FALSE;
-      break;
-    } /* end of big switch */
-
-    if (handleDefault && defaultHandler)
-      reportDefault(parser, enc, s, next);
-
-    switch (ps_parsing) {
-    case XML_SUSPENDED:
-      *nextPtr = next;
-      return XML_ERROR_NONE;
-    case XML_FINISHED:
-      return XML_ERROR_ABORTED;
-    default:
-      s = next;
-      tok = XmlPrologTok(enc, s, end, &next);
-    }
-  }
-  /* not reached */
-}
-
-static enum XML_Error PTRCALL
-epilogProcessor(XML_Parser parser,
-                const char *s,
-                const char *end,
-                const char **nextPtr)
-{
-  processor = epilogProcessor;
-  eventPtr = s;
-  for (;;) {
-    const char *next = NULL;
-    int tok = XmlPrologTok(encoding, s, end, &next);
-    eventEndPtr = next;
-    switch (tok) {
-    /* report partial linebreak - it might be the last token */
-    case -XML_TOK_PROLOG_S:
-      if (defaultHandler) {
-        reportDefault(parser, encoding, s, next);
-        if (ps_parsing == XML_FINISHED)
-          return XML_ERROR_ABORTED;
-      }
-      *nextPtr = next;
-      return XML_ERROR_NONE;
-    case XML_TOK_NONE:
-      *nextPtr = s;
-      return XML_ERROR_NONE;
-    case XML_TOK_PROLOG_S:
-      if (defaultHandler)
-        reportDefault(parser, encoding, s, next);
-      break;
-    case XML_TOK_PI:
-      if (!reportProcessingInstruction(parser, encoding, s, next))
-        return XML_ERROR_NO_MEMORY;
-      break;
-    case XML_TOK_COMMENT:
-      if (!reportComment(parser, encoding, s, next))
-        return XML_ERROR_NO_MEMORY;
-      break;
-    case XML_TOK_INVALID:
-      eventPtr = next;
-      return XML_ERROR_INVALID_TOKEN;
-    case XML_TOK_PARTIAL:
-      if (!ps_finalBuffer) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      return XML_ERROR_UNCLOSED_TOKEN;
-    case XML_TOK_PARTIAL_CHAR:
-      if (!ps_finalBuffer) {
-        *nextPtr = s;
-        return XML_ERROR_NONE;
-      }
-      return XML_ERROR_PARTIAL_CHAR;
-    default:
-      return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
-    }
-    eventPtr = s = next;
-    switch (ps_parsing) {
-    case XML_SUSPENDED:
-      *nextPtr = next;
-      return XML_ERROR_NONE;
-    case XML_FINISHED:
-      return XML_ERROR_ABORTED;
-    default: ;
-    }
-  }
-}
-
-static enum XML_Error
-processInternalEntity(XML_Parser parser, ENTITY *entity,
-                      XML_Bool betweenDecl)
-{
-  const char *textStart, *textEnd;
-  const char *next;
-  enum XML_Error result;
-  OPEN_INTERNAL_ENTITY *openEntity;
-
-  if (freeInternalEntities) {
-    openEntity = freeInternalEntities;
-    freeInternalEntities = openEntity->next;
-  }
-  else {
-    openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY));
-    if (!openEntity)
-      return XML_ERROR_NO_MEMORY;
-  }
-  entity->open = XML_TRUE;
-  entity->processed = 0;
-  openEntity->next = openInternalEntities;
-  openInternalEntities = openEntity;
-  openEntity->entity = entity;
-  openEntity->startTagLevel = tagLevel;
-  openEntity->betweenDecl = betweenDecl;
-  openEntity->internalEventPtr = NULL;
-  openEntity->internalEventEndPtr = NULL;
-  textStart = (char *)entity->textPtr;
-  textEnd = (char *)(entity->textPtr + entity->textLen);
-
-#ifdef XML_DTD
-  if (entity->is_param) {
-    int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
-    result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
-                      next, &next, XML_FALSE);
-  }
-  else
-#endif /* XML_DTD */
-    result = doContent(parser, tagLevel, internalEncoding, textStart,
-                       textEnd, &next, XML_FALSE);
-
-  if (result == XML_ERROR_NONE) {
-    if (textEnd != next && ps_parsing == XML_SUSPENDED) {
-      entity->processed = (int)(next - textStart);
-      processor = internalEntityProcessor;
-    }
-    else {
-      entity->open = XML_FALSE;
-      openInternalEntities = openEntity->next;
-      /* put openEntity back in list of free instances */
-      openEntity->next = freeInternalEntities;
-      freeInternalEntities = openEntity;
-    }
-  }
-  return result;
-}
-
-static enum XML_Error PTRCALL
-internalEntityProcessor(XML_Parser parser,
-                        const char *s,
-                        const char *end,
-                        const char **nextPtr)
-{
-  ENTITY *entity;
-  const char *textStart, *textEnd;
-  const char *next;
-  enum XML_Error result;
-  OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities;
-  if (!openEntity)
-    return XML_ERROR_UNEXPECTED_STATE;
-
-  entity = openEntity->entity;
-  textStart = ((char *)entity->textPtr) + entity->processed;
-  textEnd = (char *)(entity->textPtr + entity->textLen);
-
-#ifdef XML_DTD
-  if (entity->is_param) {
-    int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
-    result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
-                      next, &next, XML_FALSE);
-  }
-  else
-#endif /* XML_DTD */
-    result = doContent(parser, openEntity->startTagLevel, internalEncoding,
-                       textStart, textEnd, &next, XML_FALSE);
-
-  if (result != XML_ERROR_NONE)
-    return result;
-  else if (textEnd != next && ps_parsing == XML_SUSPENDED) {
-    entity->processed = (int)(next - (char *)entity->textPtr);
-    return result;
-  }
-  else {
-    entity->open = XML_FALSE;
-    openInternalEntities = openEntity->next;
-    /* put openEntity back in list of free instances */
-    openEntity->next = freeInternalEntities;
-    freeInternalEntities = openEntity;
-  }
-
-#ifdef XML_DTD
-  if (entity->is_param) {
-    int tok;
-    processor = prologProcessor;
-    tok = XmlPrologTok(encoding, s, end, &next);
-    return doProlog(parser, encoding, s, end, tok, next, nextPtr,
-                    (XML_Bool)!ps_finalBuffer);
-  }
-  else
-#endif /* XML_DTD */
-  {
-    processor = contentProcessor;
-    /* see externalEntityContentProcessor vs contentProcessor */
-    return doContent(parser, parentParser ? 1 : 0, encoding, s, end,
-                     nextPtr, (XML_Bool)!ps_finalBuffer);
-  }
-}
-
-static enum XML_Error PTRCALL
-errorProcessor(XML_Parser parser,
-               const char *UNUSED_P(s),
-               const char *UNUSED_P(end),
-               const char **UNUSED_P(nextPtr))
-{
-  return errorCode;
-}
-
-static enum XML_Error
-storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
-                    const char *ptr, const char *end,
-                    STRING_POOL *pool)
-{
-  enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr,
-                                               end, pool);
-  if (result)
-    return result;
-  if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
-    poolChop(pool);
-  if (!poolAppendChar(pool, XML_T('\0')))
-    return XML_ERROR_NO_MEMORY;
-  return XML_ERROR_NONE;
-}
-
-static enum XML_Error
-appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
-                     const char *ptr, const char *end,
-                     STRING_POOL *pool)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  for (;;) {
-    const char *next;
-    int tok = XmlAttributeValueTok(enc, ptr, end, &next);
-    switch (tok) {
-    case XML_TOK_NONE:
-      return XML_ERROR_NONE;
-    case XML_TOK_INVALID:
-      if (enc == encoding)
-        eventPtr = next;
-      return XML_ERROR_INVALID_TOKEN;
-    case XML_TOK_PARTIAL:
-      if (enc == encoding)
-        eventPtr = ptr;
-      return XML_ERROR_INVALID_TOKEN;
-    case XML_TOK_CHAR_REF:
-      {
-        XML_Char buf[XML_ENCODE_MAX];
-        int i;
-        int n = XmlCharRefNumber(enc, ptr);
-        if (n < 0) {
-          if (enc == encoding)
-            eventPtr = ptr;
-          return XML_ERROR_BAD_CHAR_REF;
-        }
-        if (!isCdata
-            && n == 0x20 /* space */
-            && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
-          break;
-        n = XmlEncode(n, (ICHAR *)buf);
-        if (!n) {
-          if (enc == encoding)
-            eventPtr = ptr;
-          return XML_ERROR_BAD_CHAR_REF;
-        }
-        for (i = 0; i < n; i++) {
-          if (!poolAppendChar(pool, buf[i]))
-            return XML_ERROR_NO_MEMORY;
-        }
-      }
-      break;
-    case XML_TOK_DATA_CHARS:
-      if (!poolAppend(pool, enc, ptr, next))
-        return XML_ERROR_NO_MEMORY;
-      break;
-    case XML_TOK_TRAILING_CR:
-      next = ptr + enc->minBytesPerChar;
-      /* fall through */
-    case XML_TOK_ATTRIBUTE_VALUE_S:
-    case XML_TOK_DATA_NEWLINE:
-      if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
-        break;
-      if (!poolAppendChar(pool, 0x20))
-        return XML_ERROR_NO_MEMORY;
-      break;
-    case XML_TOK_ENTITY_REF:
-      {
-        const XML_Char *name;
-        ENTITY *entity;
-        char checkEntityDecl;
-        XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
-                                              ptr + enc->minBytesPerChar,
-                                              next - enc->minBytesPerChar);
-        if (ch) {
-          if (!poolAppendChar(pool, ch))
-                return XML_ERROR_NO_MEMORY;
-          break;
-        }
-        name = poolStoreString(&temp2Pool, enc,
-                               ptr + enc->minBytesPerChar,
-                               next - enc->minBytesPerChar);
-        if (!name)
-          return XML_ERROR_NO_MEMORY;
-        entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
-        poolDiscard(&temp2Pool);
-        /* First, determine if a check for an existing declaration is needed;
-           if yes, check that the entity exists, and that it is internal.
-        */
-        if (pool == &dtd->pool)  /* are we called from prolog? */
-          checkEntityDecl =
-#ifdef XML_DTD
-              prologState.documentEntity &&
-#endif /* XML_DTD */
-              (dtd->standalone
-               ? !openInternalEntities
-               : !dtd->hasParamEntityRefs);
-        else /* if (pool == &tempPool): we are called from content */
-          checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone;
-        if (checkEntityDecl) {
-          if (!entity)
-            return XML_ERROR_UNDEFINED_ENTITY;
-          else if (!entity->is_internal)
-            return XML_ERROR_ENTITY_DECLARED_IN_PE;
-        }
-        else if (!entity) {
-          /* Cannot report skipped entity here - see comments on
-             skippedEntityHandler.
-          if (skippedEntityHandler)
-            skippedEntityHandler(handlerArg, name, 0);
-          */
-          /* Cannot call the default handler because this would be
-             out of sync with the call to the startElementHandler.
-          if ((pool == &tempPool) && defaultHandler)
-            reportDefault(parser, enc, ptr, next);
-          */
-          break;
-        }
-        if (entity->open) {
-          if (enc == encoding)
-            eventPtr = ptr;
-          return XML_ERROR_RECURSIVE_ENTITY_REF;
-        }
-        if (entity->notation) {
-          if (enc == encoding)
-            eventPtr = ptr;
-          return XML_ERROR_BINARY_ENTITY_REF;
-        }
-        if (!entity->textPtr) {
-          if (enc == encoding)
-            eventPtr = ptr;
-          return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
-        }
-        else {
-          enum XML_Error result;
-          const XML_Char *textEnd = entity->textPtr + entity->textLen;
-          entity->open = XML_TRUE;
-          result = appendAttributeValue(parser, internalEncoding, isCdata,
-                                        (char *)entity->textPtr,
-                                        (char *)textEnd, pool);
-          entity->open = XML_FALSE;
-          if (result)
-            return result;
-        }
-      }
-      break;
-    default:
-      if (enc == encoding)
-        eventPtr = ptr;
-      return XML_ERROR_UNEXPECTED_STATE;
-    }
-    ptr = next;
-  }
-  /* not reached */
-}
-
-static enum XML_Error
-storeEntityValue(XML_Parser parser,
-                 const ENCODING *enc,
-                 const char *entityTextPtr,
-                 const char *entityTextEnd)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  STRING_POOL *pool = &(dtd->entityValuePool);
-  enum XML_Error result = XML_ERROR_NONE;
-#ifdef XML_DTD
-  int oldInEntityValue = prologState.inEntityValue;
-  prologState.inEntityValue = 1;
-#endif /* XML_DTD */
-  /* never return Null for the value argument in EntityDeclHandler,
-     since this would indicate an external entity; therefore we
-     have to make sure that entityValuePool.start is not null */
-  if (!pool->blocks) {
-    if (!poolGrow(pool))
-      return XML_ERROR_NO_MEMORY;
-  }
-
-  for (;;) {
-    const char *next;
-    int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
-    switch (tok) {
-    case XML_TOK_PARAM_ENTITY_REF:
-#ifdef XML_DTD
-      if (isParamEntity || enc != encoding) {
-        const XML_Char *name;
-        ENTITY *entity;
-        name = poolStoreString(&tempPool, enc,
-                               entityTextPtr + enc->minBytesPerChar,
-                               next - enc->minBytesPerChar);
-        if (!name) {
-          result = XML_ERROR_NO_MEMORY;
-          goto endEntityValue;
-        }
-        entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
-        poolDiscard(&tempPool);
-        if (!entity) {
-          /* not a well-formedness error - see XML 1.0: WFC Entity Declared */
-          /* cannot report skipped entity here - see comments on
-             skippedEntityHandler
-          if (skippedEntityHandler)
-            skippedEntityHandler(handlerArg, name, 0);
-          */
-          dtd->keepProcessing = dtd->standalone;
-          goto endEntityValue;
-        }
-        if (entity->open) {
-          if (enc == encoding)
-            eventPtr = entityTextPtr;
-          result = XML_ERROR_RECURSIVE_ENTITY_REF;
-          goto endEntityValue;
-        }
-        if (entity->systemId) {
-          if (externalEntityRefHandler) {
-            dtd->paramEntityRead = XML_FALSE;
-            entity->open = XML_TRUE;
-            if (!externalEntityRefHandler(externalEntityRefHandlerArg,
-                                          0,
-                                          entity->base,
-                                          entity->systemId,
-                                          entity->publicId)) {
-              entity->open = XML_FALSE;
-              result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
-              goto endEntityValue;
-            }
-            entity->open = XML_FALSE;
-            if (!dtd->paramEntityRead)
-              dtd->keepProcessing = dtd->standalone;
-          }
-          else
-            dtd->keepProcessing = dtd->standalone;
-        }
-        else {
-          entity->open = XML_TRUE;
-          result = storeEntityValue(parser,
-                                    internalEncoding,
-                                    (char *)entity->textPtr,
-                                    (char *)(entity->textPtr
-                                             + entity->textLen));
-          entity->open = XML_FALSE;
-          if (result)
-            goto endEntityValue;
-        }
-        break;
-      }
-#endif /* XML_DTD */
-      /* In the internal subset, PE references are not legal
-         within markup declarations, e.g entity values in this case. */
-      eventPtr = entityTextPtr;
-      result = XML_ERROR_PARAM_ENTITY_REF;
-      goto endEntityValue;
-    case XML_TOK_NONE:
-      result = XML_ERROR_NONE;
-      goto endEntityValue;
-    case XML_TOK_ENTITY_REF:
-    case XML_TOK_DATA_CHARS:
-      if (!poolAppend(pool, enc, entityTextPtr, next)) {
-        result = XML_ERROR_NO_MEMORY;
-        goto endEntityValue;
-      }
-      break;
-    case XML_TOK_TRAILING_CR:
-      next = entityTextPtr + enc->minBytesPerChar;
-      /* fall through */
-    case XML_TOK_DATA_NEWLINE:
-      if (pool->end == pool->ptr && !poolGrow(pool)) {
-              result = XML_ERROR_NO_MEMORY;
-        goto endEntityValue;
-      }
-      *(pool->ptr)++ = 0xA;
-      break;
-    case XML_TOK_CHAR_REF:
-      {
-        XML_Char buf[XML_ENCODE_MAX];
-        int i;
-        int n = XmlCharRefNumber(enc, entityTextPtr);
-        if (n < 0) {
-          if (enc == encoding)
-            eventPtr = entityTextPtr;
-          result = XML_ERROR_BAD_CHAR_REF;
-          goto endEntityValue;
-        }
-        n = XmlEncode(n, (ICHAR *)buf);
-        if (!n) {
-          if (enc == encoding)
-            eventPtr = entityTextPtr;
-          result = XML_ERROR_BAD_CHAR_REF;
-          goto endEntityValue;
-        }
-        for (i = 0; i < n; i++) {
-          if (pool->end == pool->ptr && !poolGrow(pool)) {
-            result = XML_ERROR_NO_MEMORY;
-            goto endEntityValue;
-          }
-          *(pool->ptr)++ = buf[i];
-        }
-      }
-      break;
-    case XML_TOK_PARTIAL:
-      if (enc == encoding)
-        eventPtr = entityTextPtr;
-      result = XML_ERROR_INVALID_TOKEN;
-      goto endEntityValue;
-    case XML_TOK_INVALID:
-      if (enc == encoding)
-        eventPtr = next;
-      result = XML_ERROR_INVALID_TOKEN;
-      goto endEntityValue;
-    default:
-      if (enc == encoding)
-        eventPtr = entityTextPtr;
-      result = XML_ERROR_UNEXPECTED_STATE;
-      goto endEntityValue;
-    }
-    entityTextPtr = next;
-  }
-endEntityValue:
-#ifdef XML_DTD
-  prologState.inEntityValue = oldInEntityValue;
-#endif /* XML_DTD */
-  return result;
-}
-
-static void FASTCALL
-normalizeLines(XML_Char *s)
-{
-  XML_Char *p;
-  for (;; s++) {
-    if (*s == XML_T('\0'))
-      return;
-    if (*s == 0xD)
-      break;
-  }
-  p = s;
-  do {
-    if (*s == 0xD) {
-      *p++ = 0xA;
-      if (*++s == 0xA)
-        s++;
-    }
-    else
-      *p++ = *s++;
-  } while (*s);
-  *p = XML_T('\0');
-}
-
-static int
-reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
-                            const char *start, const char *end)
-{
-  const XML_Char *target;
-  XML_Char *data;
-  const char *tem;
-  if (!processingInstructionHandler) {
-    if (defaultHandler)
-      reportDefault(parser, enc, start, end);
-    return 1;
-  }
-  start += enc->minBytesPerChar * 2;
-  tem = start + XmlNameLength(enc, start);
-  target = poolStoreString(&tempPool, enc, start, tem);
-  if (!target)
-    return 0;
-  poolFinish(&tempPool);
-  data = poolStoreString(&tempPool, enc,
-                        XmlSkipS(enc, tem),
-                        end - enc->minBytesPerChar*2);
-  if (!data)
-    return 0;
-  normalizeLines(data);
-  processingInstructionHandler(handlerArg, target, data);
-  poolClear(&tempPool);
-  return 1;
-}
-
-static int
-reportComment(XML_Parser parser, const ENCODING *enc,
-              const char *start, const char *end)
-{
-  XML_Char *data;
-  if (!commentHandler) {
-    if (defaultHandler)
-      reportDefault(parser, enc, start, end);
-    return 1;
-  }
-  data = poolStoreString(&tempPool,
-                         enc,
-                         start + enc->minBytesPerChar * 4,
-                         end - enc->minBytesPerChar * 3);
-  if (!data)
-    return 0;
-  normalizeLines(data);
-  commentHandler(handlerArg, data);
-  poolClear(&tempPool);
-  return 1;
-}
-
-static void
-reportDefault(XML_Parser parser, const ENCODING *enc,
-              const char *s, const char *end)
-{
-  if (MUST_CONVERT(enc, s)) {
-    enum XML_Convert_Result convert_res;
-    const char **eventPP;
-    const char **eventEndPP;
-    if (enc == encoding) {
-      eventPP = &eventPtr;
-      eventEndPP = &eventEndPtr;
-    }
-    else {
-      eventPP = &(openInternalEntities->internalEventPtr);
-      eventEndPP = &(openInternalEntities->internalEventEndPtr);
-    }
-    do {
-      ICHAR *dataPtr = (ICHAR *)dataBuf;
-      convert_res = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
-      *eventEndPP = s;
-      defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
-      *eventPP = s;
-    } while ((convert_res != XML_CONVERT_COMPLETED) && (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
-  }
-  else
-    defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
-}
-
-
-static int
-defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
-                XML_Bool isId, const XML_Char *value, XML_Parser parser)
-{
-  DEFAULT_ATTRIBUTE *att;
-  if (value || isId) {
-    /* The handling of default attributes gets messed up if we have
-       a default which duplicates a non-default. */
-    int i;
-    for (i = 0; i < type->nDefaultAtts; i++)
-      if (attId == type->defaultAtts[i].id)
-        return 1;
-    if (isId && !type->idAtt && !attId->xmlns)
-      type->idAtt = attId;
-  }
-  if (type->nDefaultAtts == type->allocDefaultAtts) {
-    if (type->allocDefaultAtts == 0) {
-      type->allocDefaultAtts = 8;
-      type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts
-                            * sizeof(DEFAULT_ATTRIBUTE));
-      if (!type->defaultAtts)
-        return 0;
-    }
-    else {
-      DEFAULT_ATTRIBUTE *temp;
-      int count = type->allocDefaultAtts * 2;
-      temp = (DEFAULT_ATTRIBUTE *)
-        REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
-      if (temp == NULL)
-        return 0;
-      type->allocDefaultAtts = count;
-      type->defaultAtts = temp;
-    }
-  }
-  att = type->defaultAtts + type->nDefaultAtts;
-  att->id = attId;
-  att->value = value;
-  att->isCdata = isCdata;
-  if (!isCdata)
-    attId->maybeTokenized = XML_TRUE;
-  type->nDefaultAtts += 1;
-  return 1;
-}
-
-static int
-setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  const XML_Char *name;
-  for (name = elementType->name; *name; name++) {
-    if (*name == XML_T(ASCII_COLON)) {
-      PREFIX *prefix;
-      const XML_Char *s;
-      for (s = elementType->name; s != name; s++) {
-        if (!poolAppendChar(&dtd->pool, *s))
-          return 0;
-      }
-      if (!poolAppendChar(&dtd->pool, XML_T('\0')))
-        return 0;
-      prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
-                                sizeof(PREFIX));
-      if (!prefix)
-        return 0;
-      if (prefix->name == poolStart(&dtd->pool))
-        poolFinish(&dtd->pool);
-      else
-        poolDiscard(&dtd->pool);
-      elementType->prefix = prefix;
-
-    }
-  }
-  return 1;
-}
-
-static ATTRIBUTE_ID *
-getAttributeId(XML_Parser parser, const ENCODING *enc,
-               const char *start, const char *end)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  ATTRIBUTE_ID *id;
-  const XML_Char *name;
-  if (!poolAppendChar(&dtd->pool, XML_T('\0')))
-    return NULL;
-  name = poolStoreString(&dtd->pool, enc, start, end);
-  if (!name)
-    return NULL;
-  /* skip quotation mark - its storage will be re-used (like in name[-1]) */
-  ++name;
-  id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID));
-  if (!id)
-    return NULL;
-  if (id->name != name)
-    poolDiscard(&dtd->pool);
-  else {
-    poolFinish(&dtd->pool);
-    if (!ns)
-      ;
-    else if (name[0] == XML_T(ASCII_x)
-        && name[1] == XML_T(ASCII_m)
-        && name[2] == XML_T(ASCII_l)
-        && name[3] == XML_T(ASCII_n)
-        && name[4] == XML_T(ASCII_s)
-        && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) {
-      if (name[5] == XML_T('\0'))
-        id->prefix = &dtd->defaultPrefix;
-      else
-        id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX));
-      id->xmlns = XML_TRUE;
-    }
-    else {
-      int i;
-      for (i = 0; name[i]; i++) {
-        /* attributes without prefix are *not* in the default namespace */
-        if (name[i] == XML_T(ASCII_COLON)) {
-          int j;
-          for (j = 0; j < i; j++) {
-            if (!poolAppendChar(&dtd->pool, name[j]))
-              return NULL;
-          }
-          if (!poolAppendChar(&dtd->pool, XML_T('\0')))
-            return NULL;
-          id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
-                                        sizeof(PREFIX));
-          if (!id->prefix)
-            return NULL;
-          if (id->prefix->name == poolStart(&dtd->pool))
-            poolFinish(&dtd->pool);
-          else
-            poolDiscard(&dtd->pool);
-          break;
-        }
-      }
-    }
-  }
-  return id;
-}
-
-#define CONTEXT_SEP XML_T(ASCII_FF)
-
-static const XML_Char *
-getContext(XML_Parser parser)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  HASH_TABLE_ITER iter;
-  XML_Bool needSep = XML_FALSE;
-
-  if (dtd->defaultPrefix.binding) {
-    int i;
-    int len;
-    if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
-      return NULL;
-    len = dtd->defaultPrefix.binding->uriLen;
-    if (namespaceSeparator)
-      len--;
-    for (i = 0; i < len; i++)
-      if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i]))
-        return NULL;
-    needSep = XML_TRUE;
-  }
-
-  hashTableIterInit(&iter, &(dtd->prefixes));
-  for (;;) {
-    int i;
-    int len;
-    const XML_Char *s;
-    PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
-    if (!prefix)
-      break;
-    if (!prefix->binding)
-      continue;
-    if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
-      return NULL;
-    for (s = prefix->name; *s; s++)
-      if (!poolAppendChar(&tempPool, *s))
-        return NULL;
-    if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
-      return NULL;
-    len = prefix->binding->uriLen;
-    if (namespaceSeparator)
-      len--;
-    for (i = 0; i < len; i++)
-      if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
-        return NULL;
-    needSep = XML_TRUE;
-  }
-
-
-  hashTableIterInit(&iter, &(dtd->generalEntities));
-  for (;;) {
-    const XML_Char *s;
-    ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
-    if (!e)
-      break;
-    if (!e->open)
-      continue;
-    if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
-      return NULL;
-    for (s = e->name; *s; s++)
-      if (!poolAppendChar(&tempPool, *s))
-        return 0;
-    needSep = XML_TRUE;
-  }
-
-  if (!poolAppendChar(&tempPool, XML_T('\0')))
-    return NULL;
-  return tempPool.start;
-}
-
-static XML_Bool
-setContext(XML_Parser parser, const XML_Char *context)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  const XML_Char *s = context;
-
-  while (*context != XML_T('\0')) {
-    if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
-      ENTITY *e;
-      if (!poolAppendChar(&tempPool, XML_T('\0')))
-        return XML_FALSE;
-      e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0);
-      if (e)
-        e->open = XML_TRUE;
-      if (*s != XML_T('\0'))
-        s++;
-      context = s;
-      poolDiscard(&tempPool);
-    }
-    else if (*s == XML_T(ASCII_EQUALS)) {
-      PREFIX *prefix;
-      if (poolLength(&tempPool) == 0)
-        prefix = &dtd->defaultPrefix;
-      else {
-        if (!poolAppendChar(&tempPool, XML_T('\0')))
-          return XML_FALSE;
-        prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool),
-                                  sizeof(PREFIX));
-        if (!prefix)
-          return XML_FALSE;
-        if (prefix->name == poolStart(&tempPool)) {
-          prefix->name = poolCopyString(&dtd->pool, prefix->name);
-          if (!prefix->name)
-            return XML_FALSE;
-        }
-        poolDiscard(&tempPool);
-      }
-      for (context = s + 1;
-           *context != CONTEXT_SEP && *context != XML_T('\0');
-           context++)
-        if (!poolAppendChar(&tempPool, *context))
-          return XML_FALSE;
-      if (!poolAppendChar(&tempPool, XML_T('\0')))
-        return XML_FALSE;
-      if (addBinding(parser, prefix, NULL, poolStart(&tempPool),
-                     &inheritedBindings) != XML_ERROR_NONE)
-        return XML_FALSE;
-      poolDiscard(&tempPool);
-      if (*context != XML_T('\0'))
-        ++context;
-      s = context;
-    }
-    else {
-      if (!poolAppendChar(&tempPool, *s))
-        return XML_FALSE;
-      s++;
-    }
-  }
-  return XML_TRUE;
-}
-
-static void FASTCALL
-normalizePublicId(XML_Char *publicId)
-{
-  XML_Char *p = publicId;
-  XML_Char *s;
-  for (s = publicId; *s; s++) {
-    switch (*s) {
-    case 0x20:
-    case 0xD:
-    case 0xA:
-      if (p != publicId && p[-1] != 0x20)
-        *p++ = 0x20;
-      break;
-    default:
-      *p++ = *s;
-    }
-  }
-  if (p != publicId && p[-1] == 0x20)
-    --p;
-  *p = XML_T('\0');
-}
-
-static DTD *
-dtdCreate(const XML_Memory_Handling_Suite *ms)
-{
-  DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD));
-  if (p == NULL)
-    return p;
-  poolInit(&(p->pool), ms);
-  poolInit(&(p->entityValuePool), ms);
-  hashTableInit(&(p->generalEntities), ms);
-  hashTableInit(&(p->elementTypes), ms);
-  hashTableInit(&(p->attributeIds), ms);
-  hashTableInit(&(p->prefixes), ms);
-#ifdef XML_DTD
-  p->paramEntityRead = XML_FALSE;
-  hashTableInit(&(p->paramEntities), ms);
-#endif /* XML_DTD */
-  p->defaultPrefix.name = NULL;
-  p->defaultPrefix.binding = NULL;
-
-  p->in_eldecl = XML_FALSE;
-  p->scaffIndex = NULL;
-  p->scaffold = NULL;
-  p->scaffLevel = 0;
-  p->scaffSize = 0;
-  p->scaffCount = 0;
-  p->contentStringLen = 0;
-
-  p->keepProcessing = XML_TRUE;
-  p->hasParamEntityRefs = XML_FALSE;
-  p->standalone = XML_FALSE;
-  return p;
-}
-
-static void
-dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
-{
-  HASH_TABLE_ITER iter;
-  hashTableIterInit(&iter, &(p->elementTypes));
-  for (;;) {
-    ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
-    if (!e)
-      break;
-    if (e->allocDefaultAtts != 0)
-      ms->free_fcn(e->defaultAtts);
-  }
-  hashTableClear(&(p->generalEntities));
-#ifdef XML_DTD
-  p->paramEntityRead = XML_FALSE;
-  hashTableClear(&(p->paramEntities));
-#endif /* XML_DTD */
-  hashTableClear(&(p->elementTypes));
-  hashTableClear(&(p->attributeIds));
-  hashTableClear(&(p->prefixes));
-  poolClear(&(p->pool));
-  poolClear(&(p->entityValuePool));
-  p->defaultPrefix.name = NULL;
-  p->defaultPrefix.binding = NULL;
-
-  p->in_eldecl = XML_FALSE;
-
-  ms->free_fcn(p->scaffIndex);
-  p->scaffIndex = NULL;
-  ms->free_fcn(p->scaffold);
-  p->scaffold = NULL;
-
-  p->scaffLevel = 0;
-  p->scaffSize = 0;
-  p->scaffCount = 0;
-  p->contentStringLen = 0;
-
-  p->keepProcessing = XML_TRUE;
-  p->hasParamEntityRefs = XML_FALSE;
-  p->standalone = XML_FALSE;
-}
-
-static void
-dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
-{
-  HASH_TABLE_ITER iter;
-  hashTableIterInit(&iter, &(p->elementTypes));
-  for (;;) {
-    ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
-    if (!e)
-      break;
-    if (e->allocDefaultAtts != 0)
-      ms->free_fcn(e->defaultAtts);
-  }
-  hashTableDestroy(&(p->generalEntities));
-#ifdef XML_DTD
-  hashTableDestroy(&(p->paramEntities));
-#endif /* XML_DTD */
-  hashTableDestroy(&(p->elementTypes));
-  hashTableDestroy(&(p->attributeIds));
-  hashTableDestroy(&(p->prefixes));
-  poolDestroy(&(p->pool));
-  poolDestroy(&(p->entityValuePool));
-  if (isDocEntity) {
-    ms->free_fcn(p->scaffIndex);
-    ms->free_fcn(p->scaffold);
-  }
-  ms->free_fcn(p);
-}
-
-/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise.
-   The new DTD has already been initialized.
-*/
-static int
-dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
-{
-  HASH_TABLE_ITER iter;
-
-  /* Copy the prefix table. */
-
-  hashTableIterInit(&iter, &(oldDtd->prefixes));
-  for (;;) {
-    const XML_Char *name;
-    const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
-    if (!oldP)
-      break;
-    name = poolCopyString(&(newDtd->pool), oldP->name);
-    if (!name)
-      return 0;
-    if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX)))
-      return 0;
-  }
-
-  hashTableIterInit(&iter, &(oldDtd->attributeIds));
-
-  /* Copy the attribute id table. */
-
-  for (;;) {
-    ATTRIBUTE_ID *newA;
-    const XML_Char *name;
-    const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
-
-    if (!oldA)
-      break;
-    /* Remember to allocate the scratch byte before the name. */
-    if (!poolAppendChar(&(newDtd->pool), XML_T('\0')))
-      return 0;
-    name = poolCopyString(&(newDtd->pool), oldA->name);
-    if (!name)
-      return 0;
-    ++name;
-    newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name,
-                                  sizeof(ATTRIBUTE_ID));
-    if (!newA)
-      return 0;
-    newA->maybeTokenized = oldA->maybeTokenized;
-    if (oldA->prefix) {
-      newA->xmlns = oldA->xmlns;
-      if (oldA->prefix == &oldDtd->defaultPrefix)
-        newA->prefix = &newDtd->defaultPrefix;
-      else
-        newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
-                                        oldA->prefix->name, 0);
-    }
-  }
-
-  /* Copy the element type table. */
-
-  hashTableIterInit(&iter, &(oldDtd->elementTypes));
-
-  for (;;) {
-    int i;
-    ELEMENT_TYPE *newE;
-    const XML_Char *name;
-    const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
-    if (!oldE)
-      break;
-    name = poolCopyString(&(newDtd->pool), oldE->name);
-    if (!name)
-      return 0;
-    newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name,
-                                  sizeof(ELEMENT_TYPE));
-    if (!newE)
-      return 0;
-    if (oldE->nDefaultAtts) {
-      newE->defaultAtts = (DEFAULT_ATTRIBUTE *)
-          ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
-      if (!newE->defaultAtts) {
-        ms->free_fcn(newE);
-        return 0;
-      }
-    }
-    if (oldE->idAtt)
-      newE->idAtt = (ATTRIBUTE_ID *)
-          lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0);
-    newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
-    if (oldE->prefix)
-      newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
-                                      oldE->prefix->name, 0);
-    for (i = 0; i < newE->nDefaultAtts; i++) {
-      newE->defaultAtts[i].id = (ATTRIBUTE_ID *)
-          lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
-      newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
-      if (oldE->defaultAtts[i].value) {
-        newE->defaultAtts[i].value
-            = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
-        if (!newE->defaultAtts[i].value)
-          return 0;
-      }
-      else
-        newE->defaultAtts[i].value = NULL;
-    }
-  }
-
-  /* Copy the entity tables. */
-  if (!copyEntityTable(oldParser,
-                       &(newDtd->generalEntities),
-                       &(newDtd->pool),
-                       &(oldDtd->generalEntities)))
-      return 0;
-
-#ifdef XML_DTD
-  if (!copyEntityTable(oldParser,
-                       &(newDtd->paramEntities),
-                       &(newDtd->pool),
-                       &(oldDtd->paramEntities)))
-      return 0;
-  newDtd->paramEntityRead = oldDtd->paramEntityRead;
-#endif /* XML_DTD */
-
-  newDtd->keepProcessing = oldDtd->keepProcessing;
-  newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs;
-  newDtd->standalone = oldDtd->standalone;
-
-  /* Don't want deep copying for scaffolding */
-  newDtd->in_eldecl = oldDtd->in_eldecl;
-  newDtd->scaffold = oldDtd->scaffold;
-  newDtd->contentStringLen = oldDtd->contentStringLen;
-  newDtd->scaffSize = oldDtd->scaffSize;
-  newDtd->scaffLevel = oldDtd->scaffLevel;
-  newDtd->scaffIndex = oldDtd->scaffIndex;
-
-  return 1;
-}  /* End dtdCopy */
-
-static int
-copyEntityTable(XML_Parser oldParser,
-                HASH_TABLE *newTable,
-                STRING_POOL *newPool,
-                const HASH_TABLE *oldTable)
-{
-  HASH_TABLE_ITER iter;
-  const XML_Char *cachedOldBase = NULL;
-  const XML_Char *cachedNewBase = NULL;
-
-  hashTableIterInit(&iter, oldTable);
-
-  for (;;) {
-    ENTITY *newE;
-    const XML_Char *name;
-    const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
-    if (!oldE)
-      break;
-    name = poolCopyString(newPool, oldE->name);
-    if (!name)
-      return 0;
-    newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY));
-    if (!newE)
-      return 0;
-    if (oldE->systemId) {
-      const XML_Char *tem = poolCopyString(newPool, oldE->systemId);
-      if (!tem)
-        return 0;
-      newE->systemId = tem;
-      if (oldE->base) {
-        if (oldE->base == cachedOldBase)
-          newE->base = cachedNewBase;
-        else {
-          cachedOldBase = oldE->base;
-          tem = poolCopyString(newPool, cachedOldBase);
-          if (!tem)
-            return 0;
-          cachedNewBase = newE->base = tem;
-        }
-      }
-      if (oldE->publicId) {
-        tem = poolCopyString(newPool, oldE->publicId);
-        if (!tem)
-          return 0;
-        newE->publicId = tem;
-      }
-    }
-    else {
-      const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr,
-                                            oldE->textLen);
-      if (!tem)
-        return 0;
-      newE->textPtr = tem;
-      newE->textLen = oldE->textLen;
-    }
-    if (oldE->notation) {
-      const XML_Char *tem = poolCopyString(newPool, oldE->notation);
-      if (!tem)
-        return 0;
-      newE->notation = tem;
-    }
-    newE->is_param = oldE->is_param;
-    newE->is_internal = oldE->is_internal;
-  }
-  return 1;
-}
-
-#define INIT_POWER 6
-
-static XML_Bool FASTCALL
-keyeq(KEY s1, KEY s2)
-{
-  for (; *s1 == *s2; s1++, s2++)
-    if (*s1 == 0)
-      return XML_TRUE;
-  return XML_FALSE;
-}
-
-static unsigned long FASTCALL
-hash(XML_Parser parser, KEY s)
-{
-  unsigned long h = hash_secret_salt;
-  while (*s)
-    h = CHAR_HASH(h, *s++);
-  return h;
-}
-
-static NAMED *
-lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
-{
-  size_t i;
-  if (table->size == 0) {
-    size_t tsize;
-    if (!createSize)
-      return NULL;
-    table->power = INIT_POWER;
-    /* table->size is a power of 2 */
-    table->size = (size_t)1 << INIT_POWER;
-    tsize = table->size * sizeof(NAMED *);
-    table->v = (NAMED **)table->mem->malloc_fcn(tsize);
-    if (!table->v) {
-      table->size = 0;
-      return NULL;
-    }
-    memset(table->v, 0, tsize);
-    i = hash(parser, name) & ((unsigned long)table->size - 1);
-  }
-  else {
-    unsigned long h = hash(parser, name);
-    unsigned long mask = (unsigned long)table->size - 1;
-    unsigned char step = 0;
-    i = h & mask;
-    while (table->v[i]) {
-      if (keyeq(name, table->v[i]->name))
-        return table->v[i];
-      if (!step)
-        step = PROBE_STEP(h, mask, table->power);
-      i < step ? (i += table->size - step) : (i -= step);
-    }
-    if (!createSize)
-      return NULL;
-
-    /* check for overflow (table is half full) */
-    if (table->used >> (table->power - 1)) {
-      unsigned char newPower = table->power + 1;
-      size_t newSize = (size_t)1 << newPower;
-      unsigned long newMask = (unsigned long)newSize - 1;
-      size_t tsize = newSize * sizeof(NAMED *);
-      NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
-      if (!newV)
-        return NULL;
-      memset(newV, 0, tsize);
-      for (i = 0; i < table->size; i++)
-        if (table->v[i]) {
-          unsigned long newHash = hash(parser, table->v[i]->name);
-          size_t j = newHash & newMask;
-          step = 0;
-          while (newV[j]) {
-            if (!step)
-              step = PROBE_STEP(newHash, newMask, newPower);
-            j < step ? (j += newSize - step) : (j -= step);
-          }
-          newV[j] = table->v[i];
-        }
-      table->mem->free_fcn(table->v);
-      table->v = newV;
-      table->power = newPower;
-      table->size = newSize;
-      i = h & newMask;
-      step = 0;
-      while (table->v[i]) {
-        if (!step)
-          step = PROBE_STEP(h, newMask, newPower);
-        i < step ? (i += newSize - step) : (i -= step);
-      }
-    }
-  }
-  table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize);
-  if (!table->v[i])
-    return NULL;
-  memset(table->v[i], 0, createSize);
-  table->v[i]->name = name;
-  (table->used)++;
-  return table->v[i];
-}
-
-static void FASTCALL
-hashTableClear(HASH_TABLE *table)
-{
-  size_t i;
-  for (i = 0; i < table->size; i++) {
-    table->mem->free_fcn(table->v[i]);
-    table->v[i] = NULL;
-  }
-  table->used = 0;
-}
-
-static void FASTCALL
-hashTableDestroy(HASH_TABLE *table)
-{
-  size_t i;
-  for (i = 0; i < table->size; i++)
-    table->mem->free_fcn(table->v[i]);
-  table->mem->free_fcn(table->v);
-}
-
-static void FASTCALL
-hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms)
-{
-  p->power = 0;
-  p->size = 0;
-  p->used = 0;
-  p->v = NULL;
-  p->mem = ms;
-}
-
-static void FASTCALL
-hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table)
-{
-  iter->p = table->v;
-  iter->end = iter->p + table->size;
-}
-
-static NAMED * FASTCALL
-hashTableIterNext(HASH_TABLE_ITER *iter)
-{
-  while (iter->p != iter->end) {
-    NAMED *tem = *(iter->p)++;
-    if (tem)
-      return tem;
-  }
-  return NULL;
-}
-
-static void FASTCALL
-poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms)
-{
-  pool->blocks = NULL;
-  pool->freeBlocks = NULL;
-  pool->start = NULL;
-  pool->ptr = NULL;
-  pool->end = NULL;
-  pool->mem = ms;
-}
-
-static void FASTCALL
-poolClear(STRING_POOL *pool)
-{
-  if (!pool->freeBlocks)
-    pool->freeBlocks = pool->blocks;
-  else {
-    BLOCK *p = pool->blocks;
-    while (p) {
-      BLOCK *tem = p->next;
-      p->next = pool->freeBlocks;
-      pool->freeBlocks = p;
-      p = tem;
-    }
-  }
-  pool->blocks = NULL;
-  pool->start = NULL;
-  pool->ptr = NULL;
-  pool->end = NULL;
-}
-
-static void FASTCALL
-poolDestroy(STRING_POOL *pool)
-{
-  BLOCK *p = pool->blocks;
-  while (p) {
-    BLOCK *tem = p->next;
-    pool->mem->free_fcn(p);
-    p = tem;
-  }
-  p = pool->freeBlocks;
-  while (p) {
-    BLOCK *tem = p->next;
-    pool->mem->free_fcn(p);
-    p = tem;
-  }
-}
-
-static XML_Char *
-poolAppend(STRING_POOL *pool, const ENCODING *enc,
-           const char *ptr, const char *end)
-{
-  if (!pool->ptr && !poolGrow(pool))
-    return NULL;
-  for (;;) {
-    const enum XML_Convert_Result convert_res = XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
-    if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
-      break;
-    if (!poolGrow(pool))
-      return NULL;
-  }
-  return pool->start;
-}
-
-static const XML_Char * FASTCALL
-poolCopyString(STRING_POOL *pool, const XML_Char *s)
-{
-  do {
-    if (!poolAppendChar(pool, *s))
-      return NULL;
-  } while (*s++);
-  s = pool->start;
-  poolFinish(pool);
-  return s;
-}
-
-static const XML_Char *
-poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n)
-{
-  if (!pool->ptr && !poolGrow(pool))
-    return NULL;
-  for (; n > 0; --n, s++) {
-    if (!poolAppendChar(pool, *s))
-      return NULL;
-  }
-  s = pool->start;
-  poolFinish(pool);
-  return s;
-}
-
-static const XML_Char * FASTCALL
-poolAppendString(STRING_POOL *pool, const XML_Char *s)
-{
-  while (*s) {
-    if (!poolAppendChar(pool, *s))
-      return NULL;
-    s++;
-  }
-  return pool->start;
-}
-
-static XML_Char *
-poolStoreString(STRING_POOL *pool, const ENCODING *enc,
-                const char *ptr, const char *end)
-{
-  if (!poolAppend(pool, enc, ptr, end))
-    return NULL;
-  if (pool->ptr == pool->end && !poolGrow(pool))
-    return NULL;
-  *(pool->ptr)++ = 0;
-  return pool->start;
-}
-
-static XML_Bool FASTCALL
-poolGrow(STRING_POOL *pool)
-{
-  if (pool->freeBlocks) {
-    if (pool->start == 0) {
-      pool->blocks = pool->freeBlocks;
-      pool->freeBlocks = pool->freeBlocks->next;
-      pool->blocks->next = NULL;
-      pool->start = pool->blocks->s;
-      pool->end = pool->start + pool->blocks->size;
-      pool->ptr = pool->start;
-      return XML_TRUE;
-    }
-    if (pool->end - pool->start < pool->freeBlocks->size) {
-      BLOCK *tem = pool->freeBlocks->next;
-      pool->freeBlocks->next = pool->blocks;
-      pool->blocks = pool->freeBlocks;
-      pool->freeBlocks = tem;
-      memcpy(pool->blocks->s, pool->start,
-             (pool->end - pool->start) * sizeof(XML_Char));
-      pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
-      pool->start = pool->blocks->s;
-      pool->end = pool->start + pool->blocks->size;
-      return XML_TRUE;
-    }
-  }
-  if (pool->blocks && pool->start == pool->blocks->s) {
-    BLOCK *temp;
-    int blockSize = (int)((unsigned)(pool->end - pool->start)*2U);
-
-    if (blockSize < 0)
-      return XML_FALSE;
-
-    temp = (BLOCK *)
-      pool->mem->realloc_fcn(pool->blocks,
-                             (offsetof(BLOCK, s)
-                              + blockSize * sizeof(XML_Char)));
-    if (temp == NULL)
-      return XML_FALSE;
-    pool->blocks = temp;
-    pool->blocks->size = blockSize;
-    pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
-    pool->start = pool->blocks->s;
-    pool->end = pool->start + blockSize;
-  }
-  else {
-    BLOCK *tem;
-    int blockSize = (int)(pool->end - pool->start);
-
-    if (blockSize < 0)
-      return XML_FALSE;
-
-    if (blockSize < INIT_BLOCK_SIZE)
-      blockSize = INIT_BLOCK_SIZE;
-    else
-      blockSize *= 2;
-    tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s)
-                                        + blockSize * sizeof(XML_Char));
-    if (!tem)
-      return XML_FALSE;
-    tem->size = blockSize;
-    tem->next = pool->blocks;
-    pool->blocks = tem;
-    if (pool->ptr != pool->start)
-      memcpy(tem->s, pool->start,
-             (pool->ptr - pool->start) * sizeof(XML_Char));
-    pool->ptr = tem->s + (pool->ptr - pool->start);
-    pool->start = tem->s;
-    pool->end = tem->s + blockSize;
-  }
-  return XML_TRUE;
-}
-
-static int FASTCALL
-nextScaffoldPart(XML_Parser parser)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  CONTENT_SCAFFOLD * me;
-  int next;
-
-  if (!dtd->scaffIndex) {
-    dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int));
-    if (!dtd->scaffIndex)
-      return -1;
-    dtd->scaffIndex[0] = 0;
-  }
-
-  if (dtd->scaffCount >= dtd->scaffSize) {
-    CONTENT_SCAFFOLD *temp;
-    if (dtd->scaffold) {
-      temp = (CONTENT_SCAFFOLD *)
-        REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
-      if (temp == NULL)
-        return -1;
-      dtd->scaffSize *= 2;
-    }
-    else {
-      temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS
-                                        * sizeof(CONTENT_SCAFFOLD));
-      if (temp == NULL)
-        return -1;
-      dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS;
-    }
-    dtd->scaffold = temp;
-  }
-  next = dtd->scaffCount++;
-  me = &dtd->scaffold[next];
-  if (dtd->scaffLevel) {
-    CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]];
-    if (parent->lastchild) {
-      dtd->scaffold[parent->lastchild].nextsib = next;
-    }
-    if (!parent->childcnt)
-      parent->firstchild = next;
-    parent->lastchild = next;
-    parent->childcnt++;
-  }
-  me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0;
-  return next;
-}
-
-static void
-build_node(XML_Parser parser,
-           int src_node,
-           XML_Content *dest,
-           XML_Content **contpos,
-           XML_Char **strpos)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  dest->type = dtd->scaffold[src_node].type;
-  dest->quant = dtd->scaffold[src_node].quant;
-  if (dest->type == XML_CTYPE_NAME) {
-    const XML_Char *src;
-    dest->name = *strpos;
-    src = dtd->scaffold[src_node].name;
-    for (;;) {
-      *(*strpos)++ = *src;
-      if (!*src)
-        break;
-      src++;
-    }
-    dest->numchildren = 0;
-    dest->children = NULL;
-  }
-  else {
-    unsigned int i;
-    int cn;
-    dest->numchildren = dtd->scaffold[src_node].childcnt;
-    dest->children = *contpos;
-    *contpos += dest->numchildren;
-    for (i = 0, cn = dtd->scaffold[src_node].firstchild;
-         i < dest->numchildren;
-         i++, cn = dtd->scaffold[cn].nextsib) {
-      build_node(parser, cn, &(dest->children[i]), contpos, strpos);
-    }
-    dest->name = NULL;
-  }
-}
-
-static XML_Content *
-build_model (XML_Parser parser)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  XML_Content *ret;
-  XML_Content *cpos;
-  XML_Char * str;
-  int allocsize = (dtd->scaffCount * sizeof(XML_Content)
-                   + (dtd->contentStringLen * sizeof(XML_Char)));
-
-  ret = (XML_Content *)MALLOC(allocsize);
-  if (!ret)
-    return NULL;
-
-  str =  (XML_Char *) (&ret[dtd->scaffCount]);
-  cpos = &ret[1];
-
-  build_node(parser, 0, ret, &cpos, &str);
-  return ret;
-}
-
-static ELEMENT_TYPE *
-getElementType(XML_Parser parser,
-               const ENCODING *enc,
-               const char *ptr,
-               const char *end)
-{
-  DTD * const dtd = _dtd;  /* save one level of indirection */
-  const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end);
-  ELEMENT_TYPE *ret;
-
-  if (!name)
-    return NULL;
-  ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE));
-  if (!ret)
-    return NULL;
-  if (ret->name != name)
-    poolDiscard(&dtd->pool);
-  else {
-    poolFinish(&dtd->pool);
-    if (!setElementTypePrefix(parser, ret))
-      return NULL;
-  }
-  return ret;
-}
diff --git a/components/expat/library/xmlrole.c b/components/expat/library/xmlrole.c
deleted file mode 100644 (file)
index fcd0dc6..0000000
+++ /dev/null
@@ -1,1336 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-#include <stddef.h>
-
-#ifdef WIN32
-#include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
-#else
-#ifdef HAVE_EXPAT_CONFIG_H
-#include <expat_config.h>
-#endif
-#endif /* ndef WIN32 */
-
-#include "expat_external.h"
-#include "internal.h"
-#include "xmlrole.h"
-#include "ascii.h"
-
-/* Doesn't check:
-
- that ,| are not mixed in a model group
- content of literals
-
-*/
-
-static const char KW_ANY[] = {
-    ASCII_A, ASCII_N, ASCII_Y, '\0' };
-static const char KW_ATTLIST[] = {
-    ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' };
-static const char KW_CDATA[] = {
-    ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
-static const char KW_DOCTYPE[] = {
-    ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' };
-static const char KW_ELEMENT[] = {
-    ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' };
-static const char KW_EMPTY[] = {
-    ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' };
-static const char KW_ENTITIES[] = {
-    ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S,
-    '\0' };
-static const char KW_ENTITY[] = {
-    ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
-static const char KW_FIXED[] = {
-    ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' };
-static const char KW_ID[] = {
-    ASCII_I, ASCII_D, '\0' };
-static const char KW_IDREF[] = {
-    ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
-static const char KW_IDREFS[] = {
-    ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
-#ifdef XML_DTD
-static const char KW_IGNORE[] = {
-    ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' };
-#endif
-static const char KW_IMPLIED[] = {
-    ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' };
-#ifdef XML_DTD
-static const char KW_INCLUDE[] = {
-    ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' };
-#endif
-static const char KW_NDATA[] = {
-    ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
-static const char KW_NMTOKEN[] = {
-    ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
-static const char KW_NMTOKENS[] = {
-    ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S,
-    '\0' };
-static const char KW_NOTATION[] =
-    { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N,
-      '\0' };
-static const char KW_PCDATA[] = {
-    ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
-static const char KW_PUBLIC[] = {
-    ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' };
-static const char KW_REQUIRED[] = {
-    ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D,
-    '\0' };
-static const char KW_SYSTEM[] = {
-    ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' };
-
-#ifndef MIN_BYTES_PER_CHAR
-#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar)
-#endif
-
-#ifdef XML_DTD
-#define setTopLevel(state) \
-  ((state)->handler = ((state)->documentEntity \
-                       ? internalSubset \
-                       : externalSubset1))
-#else /* not XML_DTD */
-#define setTopLevel(state) ((state)->handler = internalSubset)
-#endif /* not XML_DTD */
-
-typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state,
-                                   int tok,
-                                   const char *ptr,
-                                   const char *end,
-                                   const ENCODING *enc);
-
-static PROLOG_HANDLER
-  prolog0, prolog1, prolog2,
-  doctype0, doctype1, doctype2, doctype3, doctype4, doctype5,
-  internalSubset,
-  entity0, entity1, entity2, entity3, entity4, entity5, entity6,
-  entity7, entity8, entity9, entity10,
-  notation0, notation1, notation2, notation3, notation4,
-  attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6,
-  attlist7, attlist8, attlist9,
-  element0, element1, element2, element3, element4, element5, element6,
-  element7,
-#ifdef XML_DTD
-  externalSubset0, externalSubset1,
-  condSect0, condSect1, condSect2,
-#endif /* XML_DTD */
-  declClose,
-  error;
-
-static int FASTCALL common(PROLOG_STATE *state, int tok);
-
-static int PTRCALL
-prolog0(PROLOG_STATE *state,
-        int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    state->handler = prolog1;
-    return XML_ROLE_NONE;
-  case XML_TOK_XML_DECL:
-    state->handler = prolog1;
-    return XML_ROLE_XML_DECL;
-  case XML_TOK_PI:
-    state->handler = prolog1;
-    return XML_ROLE_PI;
-  case XML_TOK_COMMENT:
-    state->handler = prolog1;
-    return XML_ROLE_COMMENT;
-  case XML_TOK_BOM:
-    return XML_ROLE_NONE;
-  case XML_TOK_DECL_OPEN:
-    if (!XmlNameMatchesAscii(enc,
-                             ptr + 2 * MIN_BYTES_PER_CHAR(enc),
-                             end,
-                             KW_DOCTYPE))
-      break;
-    state->handler = doctype0;
-    return XML_ROLE_DOCTYPE_NONE;
-  case XML_TOK_INSTANCE_START:
-    state->handler = error;
-    return XML_ROLE_INSTANCE_START;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-prolog1(PROLOG_STATE *state,
-        int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NONE;
-  case XML_TOK_PI:
-    return XML_ROLE_PI;
-  case XML_TOK_COMMENT:
-    return XML_ROLE_COMMENT;
-  case XML_TOK_BOM:
-    return XML_ROLE_NONE;
-  case XML_TOK_DECL_OPEN:
-    if (!XmlNameMatchesAscii(enc,
-                             ptr + 2 * MIN_BYTES_PER_CHAR(enc),
-                             end,
-                             KW_DOCTYPE))
-      break;
-    state->handler = doctype0;
-    return XML_ROLE_DOCTYPE_NONE;
-  case XML_TOK_INSTANCE_START:
-    state->handler = error;
-    return XML_ROLE_INSTANCE_START;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-prolog2(PROLOG_STATE *state,
-        int tok,
-        const char *UNUSED_P(ptr),
-        const char *UNUSED_P(end),
-        const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NONE;
-  case XML_TOK_PI:
-    return XML_ROLE_PI;
-  case XML_TOK_COMMENT:
-    return XML_ROLE_COMMENT;
-  case XML_TOK_INSTANCE_START:
-    state->handler = error;
-    return XML_ROLE_INSTANCE_START;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-doctype0(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_DOCTYPE_NONE;
-  case XML_TOK_NAME:
-  case XML_TOK_PREFIXED_NAME:
-    state->handler = doctype1;
-    return XML_ROLE_DOCTYPE_NAME;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-doctype1(PROLOG_STATE *state,
-         int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_DOCTYPE_NONE;
-  case XML_TOK_OPEN_BRACKET:
-    state->handler = internalSubset;
-    return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
-  case XML_TOK_DECL_CLOSE:
-    state->handler = prolog2;
-    return XML_ROLE_DOCTYPE_CLOSE;
-  case XML_TOK_NAME:
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
-      state->handler = doctype3;
-      return XML_ROLE_DOCTYPE_NONE;
-    }
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
-      state->handler = doctype2;
-      return XML_ROLE_DOCTYPE_NONE;
-    }
-    break;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-doctype2(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_DOCTYPE_NONE;
-  case XML_TOK_LITERAL:
-    state->handler = doctype3;
-    return XML_ROLE_DOCTYPE_PUBLIC_ID;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-doctype3(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_DOCTYPE_NONE;
-  case XML_TOK_LITERAL:
-    state->handler = doctype4;
-    return XML_ROLE_DOCTYPE_SYSTEM_ID;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-doctype4(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_DOCTYPE_NONE;
-  case XML_TOK_OPEN_BRACKET:
-    state->handler = internalSubset;
-    return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
-  case XML_TOK_DECL_CLOSE:
-    state->handler = prolog2;
-    return XML_ROLE_DOCTYPE_CLOSE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-doctype5(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_DOCTYPE_NONE;
-  case XML_TOK_DECL_CLOSE:
-    state->handler = prolog2;
-    return XML_ROLE_DOCTYPE_CLOSE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-internalSubset(PROLOG_STATE *state,
-               int tok,
-               const char *ptr,
-               const char *end,
-               const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NONE;
-  case XML_TOK_DECL_OPEN:
-    if (XmlNameMatchesAscii(enc,
-                            ptr + 2 * MIN_BYTES_PER_CHAR(enc),
-                            end,
-                            KW_ENTITY)) {
-      state->handler = entity0;
-      return XML_ROLE_ENTITY_NONE;
-    }
-    if (XmlNameMatchesAscii(enc,
-                            ptr + 2 * MIN_BYTES_PER_CHAR(enc),
-                            end,
-                            KW_ATTLIST)) {
-      state->handler = attlist0;
-      return XML_ROLE_ATTLIST_NONE;
-    }
-    if (XmlNameMatchesAscii(enc,
-                            ptr + 2 * MIN_BYTES_PER_CHAR(enc),
-                            end,
-                            KW_ELEMENT)) {
-      state->handler = element0;
-      return XML_ROLE_ELEMENT_NONE;
-    }
-    if (XmlNameMatchesAscii(enc,
-                            ptr + 2 * MIN_BYTES_PER_CHAR(enc),
-                            end,
-                            KW_NOTATION)) {
-      state->handler = notation0;
-      return XML_ROLE_NOTATION_NONE;
-    }
-    break;
-  case XML_TOK_PI:
-    return XML_ROLE_PI;
-  case XML_TOK_COMMENT:
-    return XML_ROLE_COMMENT;
-  case XML_TOK_PARAM_ENTITY_REF:
-    return XML_ROLE_PARAM_ENTITY_REF;
-  case XML_TOK_CLOSE_BRACKET:
-    state->handler = doctype5;
-    return XML_ROLE_DOCTYPE_NONE;
-  case XML_TOK_NONE:
-    return XML_ROLE_NONE;
-  }
-  return common(state, tok);
-}
-
-#ifdef XML_DTD
-
-static int PTRCALL
-externalSubset0(PROLOG_STATE *state,
-                int tok,
-                const char *ptr,
-                const char *end,
-                const ENCODING *enc)
-{
-  state->handler = externalSubset1;
-  if (tok == XML_TOK_XML_DECL)
-    return XML_ROLE_TEXT_DECL;
-  return externalSubset1(state, tok, ptr, end, enc);
-}
-
-static int PTRCALL
-externalSubset1(PROLOG_STATE *state,
-                int tok,
-                const char *ptr,
-                const char *end,
-                const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_COND_SECT_OPEN:
-    state->handler = condSect0;
-    return XML_ROLE_NONE;
-  case XML_TOK_COND_SECT_CLOSE:
-    if (state->includeLevel == 0)
-      break;
-    state->includeLevel -= 1;
-    return XML_ROLE_NONE;
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NONE;
-  case XML_TOK_CLOSE_BRACKET:
-    break;
-  case XML_TOK_NONE:
-    if (state->includeLevel)
-      break;
-    return XML_ROLE_NONE;
-  default:
-    return internalSubset(state, tok, ptr, end, enc);
-  }
-  return common(state, tok);
-}
-
-#endif /* XML_DTD */
-
-static int PTRCALL
-entity0(PROLOG_STATE *state,
-        int tok,
-        const char *UNUSED_P(ptr),
-        const char *UNUSED_P(end),
-        const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_PERCENT:
-    state->handler = entity1;
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_NAME:
-    state->handler = entity2;
-    return XML_ROLE_GENERAL_ENTITY_NAME;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-entity1(PROLOG_STATE *state,
-        int tok,
-        const char *UNUSED_P(ptr),
-        const char *UNUSED_P(end),
-        const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_NAME:
-    state->handler = entity7;
-    return XML_ROLE_PARAM_ENTITY_NAME;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-entity2(PROLOG_STATE *state,
-        int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_NAME:
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
-      state->handler = entity4;
-      return XML_ROLE_ENTITY_NONE;
-    }
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
-      state->handler = entity3;
-      return XML_ROLE_ENTITY_NONE;
-    }
-    break;
-  case XML_TOK_LITERAL:
-    state->handler = declClose;
-    state->role_none = XML_ROLE_ENTITY_NONE;
-    return XML_ROLE_ENTITY_VALUE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-entity3(PROLOG_STATE *state,
-        int tok,
-        const char *UNUSED_P(ptr),
-        const char *UNUSED_P(end),
-        const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_LITERAL:
-    state->handler = entity4;
-    return XML_ROLE_ENTITY_PUBLIC_ID;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-entity4(PROLOG_STATE *state,
-        int tok,
-        const char *UNUSED_P(ptr),
-        const char *UNUSED_P(end),
-        const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_LITERAL:
-    state->handler = entity5;
-    return XML_ROLE_ENTITY_SYSTEM_ID;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-entity5(PROLOG_STATE *state,
-        int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_DECL_CLOSE:
-    setTopLevel(state);
-    return XML_ROLE_ENTITY_COMPLETE;
-  case XML_TOK_NAME:
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) {
-      state->handler = entity6;
-      return XML_ROLE_ENTITY_NONE;
-    }
-    break;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-entity6(PROLOG_STATE *state,
-        int tok,
-        const char *UNUSED_P(ptr),
-        const char *UNUSED_P(end),
-        const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_NAME:
-    state->handler = declClose;
-    state->role_none = XML_ROLE_ENTITY_NONE;
-    return XML_ROLE_ENTITY_NOTATION_NAME;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-entity7(PROLOG_STATE *state,
-        int tok,
-        const char *ptr,
-        const char *end,
-        const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_NAME:
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
-      state->handler = entity9;
-      return XML_ROLE_ENTITY_NONE;
-    }
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
-      state->handler = entity8;
-      return XML_ROLE_ENTITY_NONE;
-    }
-    break;
-  case XML_TOK_LITERAL:
-    state->handler = declClose;
-    state->role_none = XML_ROLE_ENTITY_NONE;
-    return XML_ROLE_ENTITY_VALUE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-entity8(PROLOG_STATE *state,
-        int tok,
-        const char *UNUSED_P(ptr),
-        const char *UNUSED_P(end),
-        const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_LITERAL:
-    state->handler = entity9;
-    return XML_ROLE_ENTITY_PUBLIC_ID;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-entity9(PROLOG_STATE *state,
-        int tok,
-        const char *UNUSED_P(ptr),
-        const char *UNUSED_P(end),
-        const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_LITERAL:
-    state->handler = entity10;
-    return XML_ROLE_ENTITY_SYSTEM_ID;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-entity10(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ENTITY_NONE;
-  case XML_TOK_DECL_CLOSE:
-    setTopLevel(state);
-    return XML_ROLE_ENTITY_COMPLETE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-notation0(PROLOG_STATE *state,
-          int tok,
-          const char *UNUSED_P(ptr),
-          const char *UNUSED_P(end),
-          const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NOTATION_NONE;
-  case XML_TOK_NAME:
-    state->handler = notation1;
-    return XML_ROLE_NOTATION_NAME;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-notation1(PROLOG_STATE *state,
-          int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NOTATION_NONE;
-  case XML_TOK_NAME:
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
-      state->handler = notation3;
-      return XML_ROLE_NOTATION_NONE;
-    }
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
-      state->handler = notation2;
-      return XML_ROLE_NOTATION_NONE;
-    }
-    break;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-notation2(PROLOG_STATE *state,
-          int tok,
-          const char *UNUSED_P(ptr),
-          const char *UNUSED_P(end),
-          const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NOTATION_NONE;
-  case XML_TOK_LITERAL:
-    state->handler = notation4;
-    return XML_ROLE_NOTATION_PUBLIC_ID;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-notation3(PROLOG_STATE *state,
-          int tok,
-          const char *UNUSED_P(ptr),
-          const char *UNUSED_P(end),
-          const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NOTATION_NONE;
-  case XML_TOK_LITERAL:
-    state->handler = declClose;
-    state->role_none = XML_ROLE_NOTATION_NONE;
-    return XML_ROLE_NOTATION_SYSTEM_ID;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-notation4(PROLOG_STATE *state,
-          int tok,
-          const char *UNUSED_P(ptr),
-          const char *UNUSED_P(end),
-          const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NOTATION_NONE;
-  case XML_TOK_LITERAL:
-    state->handler = declClose;
-    state->role_none = XML_ROLE_NOTATION_NONE;
-    return XML_ROLE_NOTATION_SYSTEM_ID;
-  case XML_TOK_DECL_CLOSE:
-    setTopLevel(state);
-    return XML_ROLE_NOTATION_NO_SYSTEM_ID;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-attlist0(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_NAME:
-  case XML_TOK_PREFIXED_NAME:
-    state->handler = attlist1;
-    return XML_ROLE_ATTLIST_ELEMENT_NAME;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-attlist1(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_DECL_CLOSE:
-    setTopLevel(state);
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_NAME:
-  case XML_TOK_PREFIXED_NAME:
-    state->handler = attlist2;
-    return XML_ROLE_ATTRIBUTE_NAME;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-attlist2(PROLOG_STATE *state,
-         int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_NAME:
-    {
-      static const char * const types[] = {
-        KW_CDATA,
-        KW_ID,
-        KW_IDREF,
-        KW_IDREFS,
-        KW_ENTITY,
-        KW_ENTITIES,
-        KW_NMTOKEN,
-        KW_NMTOKENS,
-      };
-      int i;
-      for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++)
-        if (XmlNameMatchesAscii(enc, ptr, end, types[i])) {
-          state->handler = attlist8;
-          return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i;
-        }
-    }
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) {
-      state->handler = attlist5;
-      return XML_ROLE_ATTLIST_NONE;
-    }
-    break;
-  case XML_TOK_OPEN_PAREN:
-    state->handler = attlist3;
-    return XML_ROLE_ATTLIST_NONE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-attlist3(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_NMTOKEN:
-  case XML_TOK_NAME:
-  case XML_TOK_PREFIXED_NAME:
-    state->handler = attlist4;
-    return XML_ROLE_ATTRIBUTE_ENUM_VALUE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-attlist4(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_CLOSE_PAREN:
-    state->handler = attlist8;
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_OR:
-    state->handler = attlist3;
-    return XML_ROLE_ATTLIST_NONE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-attlist5(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_OPEN_PAREN:
-    state->handler = attlist6;
-    return XML_ROLE_ATTLIST_NONE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-attlist6(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_NAME:
-    state->handler = attlist7;
-    return XML_ROLE_ATTRIBUTE_NOTATION_VALUE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-attlist7(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_CLOSE_PAREN:
-    state->handler = attlist8;
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_OR:
-    state->handler = attlist6;
-    return XML_ROLE_ATTLIST_NONE;
-  }
-  return common(state, tok);
-}
-
-/* default value */
-static int PTRCALL
-attlist8(PROLOG_STATE *state,
-         int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_POUND_NAME:
-    if (XmlNameMatchesAscii(enc,
-                            ptr + MIN_BYTES_PER_CHAR(enc),
-                            end,
-                            KW_IMPLIED)) {
-      state->handler = attlist1;
-      return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE;
-    }
-    if (XmlNameMatchesAscii(enc,
-                            ptr + MIN_BYTES_PER_CHAR(enc),
-                            end,
-                            KW_REQUIRED)) {
-      state->handler = attlist1;
-      return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE;
-    }
-    if (XmlNameMatchesAscii(enc,
-                            ptr + MIN_BYTES_PER_CHAR(enc),
-                            end,
-                            KW_FIXED)) {
-      state->handler = attlist9;
-      return XML_ROLE_ATTLIST_NONE;
-    }
-    break;
-  case XML_TOK_LITERAL:
-    state->handler = attlist1;
-    return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-attlist9(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ATTLIST_NONE;
-  case XML_TOK_LITERAL:
-    state->handler = attlist1;
-    return XML_ROLE_FIXED_ATTRIBUTE_VALUE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-element0(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ELEMENT_NONE;
-  case XML_TOK_NAME:
-  case XML_TOK_PREFIXED_NAME:
-    state->handler = element1;
-    return XML_ROLE_ELEMENT_NAME;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-element1(PROLOG_STATE *state,
-         int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ELEMENT_NONE;
-  case XML_TOK_NAME:
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) {
-      state->handler = declClose;
-      state->role_none = XML_ROLE_ELEMENT_NONE;
-      return XML_ROLE_CONTENT_EMPTY;
-    }
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) {
-      state->handler = declClose;
-      state->role_none = XML_ROLE_ELEMENT_NONE;
-      return XML_ROLE_CONTENT_ANY;
-    }
-    break;
-  case XML_TOK_OPEN_PAREN:
-    state->handler = element2;
-    state->level = 1;
-    return XML_ROLE_GROUP_OPEN;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-element2(PROLOG_STATE *state,
-         int tok,
-         const char *ptr,
-         const char *end,
-         const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ELEMENT_NONE;
-  case XML_TOK_POUND_NAME:
-    if (XmlNameMatchesAscii(enc,
-                            ptr + MIN_BYTES_PER_CHAR(enc),
-                            end,
-                            KW_PCDATA)) {
-      state->handler = element3;
-      return XML_ROLE_CONTENT_PCDATA;
-    }
-    break;
-  case XML_TOK_OPEN_PAREN:
-    state->level = 2;
-    state->handler = element6;
-    return XML_ROLE_GROUP_OPEN;
-  case XML_TOK_NAME:
-  case XML_TOK_PREFIXED_NAME:
-    state->handler = element7;
-    return XML_ROLE_CONTENT_ELEMENT;
-  case XML_TOK_NAME_QUESTION:
-    state->handler = element7;
-    return XML_ROLE_CONTENT_ELEMENT_OPT;
-  case XML_TOK_NAME_ASTERISK:
-    state->handler = element7;
-    return XML_ROLE_CONTENT_ELEMENT_REP;
-  case XML_TOK_NAME_PLUS:
-    state->handler = element7;
-    return XML_ROLE_CONTENT_ELEMENT_PLUS;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-element3(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ELEMENT_NONE;
-  case XML_TOK_CLOSE_PAREN:
-    state->handler = declClose;
-    state->role_none = XML_ROLE_ELEMENT_NONE;
-    return XML_ROLE_GROUP_CLOSE;
-  case XML_TOK_CLOSE_PAREN_ASTERISK:
-    state->handler = declClose;
-    state->role_none = XML_ROLE_ELEMENT_NONE;
-    return XML_ROLE_GROUP_CLOSE_REP;
-  case XML_TOK_OR:
-    state->handler = element4;
-    return XML_ROLE_ELEMENT_NONE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-element4(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ELEMENT_NONE;
-  case XML_TOK_NAME:
-  case XML_TOK_PREFIXED_NAME:
-    state->handler = element5;
-    return XML_ROLE_CONTENT_ELEMENT;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-element5(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ELEMENT_NONE;
-  case XML_TOK_CLOSE_PAREN_ASTERISK:
-    state->handler = declClose;
-    state->role_none = XML_ROLE_ELEMENT_NONE;
-    return XML_ROLE_GROUP_CLOSE_REP;
-  case XML_TOK_OR:
-    state->handler = element4;
-    return XML_ROLE_ELEMENT_NONE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-element6(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ELEMENT_NONE;
-  case XML_TOK_OPEN_PAREN:
-    state->level += 1;
-    return XML_ROLE_GROUP_OPEN;
-  case XML_TOK_NAME:
-  case XML_TOK_PREFIXED_NAME:
-    state->handler = element7;
-    return XML_ROLE_CONTENT_ELEMENT;
-  case XML_TOK_NAME_QUESTION:
-    state->handler = element7;
-    return XML_ROLE_CONTENT_ELEMENT_OPT;
-  case XML_TOK_NAME_ASTERISK:
-    state->handler = element7;
-    return XML_ROLE_CONTENT_ELEMENT_REP;
-  case XML_TOK_NAME_PLUS:
-    state->handler = element7;
-    return XML_ROLE_CONTENT_ELEMENT_PLUS;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-element7(PROLOG_STATE *state,
-         int tok,
-         const char *UNUSED_P(ptr),
-         const char *UNUSED_P(end),
-         const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_ELEMENT_NONE;
-  case XML_TOK_CLOSE_PAREN:
-    state->level -= 1;
-    if (state->level == 0) {
-      state->handler = declClose;
-      state->role_none = XML_ROLE_ELEMENT_NONE;
-    }
-    return XML_ROLE_GROUP_CLOSE;
-  case XML_TOK_CLOSE_PAREN_ASTERISK:
-    state->level -= 1;
-    if (state->level == 0) {
-      state->handler = declClose;
-      state->role_none = XML_ROLE_ELEMENT_NONE;
-    }
-    return XML_ROLE_GROUP_CLOSE_REP;
-  case XML_TOK_CLOSE_PAREN_QUESTION:
-    state->level -= 1;
-    if (state->level == 0) {
-      state->handler = declClose;
-      state->role_none = XML_ROLE_ELEMENT_NONE;
-    }
-    return XML_ROLE_GROUP_CLOSE_OPT;
-  case XML_TOK_CLOSE_PAREN_PLUS:
-    state->level -= 1;
-    if (state->level == 0) {
-      state->handler = declClose;
-      state->role_none = XML_ROLE_ELEMENT_NONE;
-    }
-    return XML_ROLE_GROUP_CLOSE_PLUS;
-  case XML_TOK_COMMA:
-    state->handler = element6;
-    return XML_ROLE_GROUP_SEQUENCE;
-  case XML_TOK_OR:
-    state->handler = element6;
-    return XML_ROLE_GROUP_CHOICE;
-  }
-  return common(state, tok);
-}
-
-#ifdef XML_DTD
-
-static int PTRCALL
-condSect0(PROLOG_STATE *state,
-          int tok,
-          const char *ptr,
-          const char *end,
-          const ENCODING *enc)
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NONE;
-  case XML_TOK_NAME:
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) {
-      state->handler = condSect1;
-      return XML_ROLE_NONE;
-    }
-    if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) {
-      state->handler = condSect2;
-      return XML_ROLE_NONE;
-    }
-    break;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-condSect1(PROLOG_STATE *state,
-          int tok,
-          const char *UNUSED_P(ptr),
-          const char *UNUSED_P(end),
-          const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NONE;
-  case XML_TOK_OPEN_BRACKET:
-    state->handler = externalSubset1;
-    state->includeLevel += 1;
-    return XML_ROLE_NONE;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-condSect2(PROLOG_STATE *state,
-          int tok,
-          const char *UNUSED_P(ptr),
-          const char *UNUSED_P(end),
-          const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return XML_ROLE_NONE;
-  case XML_TOK_OPEN_BRACKET:
-    state->handler = externalSubset1;
-    return XML_ROLE_IGNORE_SECT;
-  }
-  return common(state, tok);
-}
-
-#endif /* XML_DTD */
-
-static int PTRCALL
-declClose(PROLOG_STATE *state,
-          int tok,
-          const char *UNUSED_P(ptr),
-          const char *UNUSED_P(end),
-          const ENCODING *UNUSED_P(enc))
-{
-  switch (tok) {
-  case XML_TOK_PROLOG_S:
-    return state->role_none;
-  case XML_TOK_DECL_CLOSE:
-    setTopLevel(state);
-    return state->role_none;
-  }
-  return common(state, tok);
-}
-
-static int PTRCALL
-error(PROLOG_STATE *UNUSED_P(state),
-      int UNUSED_P(tok),
-      const char *UNUSED_P(ptr),
-      const char *UNUSED_P(end),
-      const ENCODING *UNUSED_P(enc))
-{
-  return XML_ROLE_NONE;
-}
-
-static int FASTCALL
-common(PROLOG_STATE *state, int tok)
-{
-#ifdef XML_DTD
-  if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF)
-    return XML_ROLE_INNER_PARAM_ENTITY_REF;
-#endif
-  state->handler = error;
-  return XML_ROLE_ERROR;
-}
-
-void
-XmlPrologStateInit(PROLOG_STATE *state)
-{
-  state->handler = prolog0;
-#ifdef XML_DTD
-  state->documentEntity = 1;
-  state->includeLevel = 0;
-  state->inEntityValue = 0;
-#endif /* XML_DTD */
-}
-
-#ifdef XML_DTD
-
-void
-XmlPrologStateInitExternalEntity(PROLOG_STATE *state)
-{
-  state->handler = externalSubset0;
-  state->documentEntity = 0;
-  state->includeLevel = 0;
-}
-
-#endif /* XML_DTD */
diff --git a/components/expat/library/xmltok.c b/components/expat/library/xmltok.c
deleted file mode 100644 (file)
index b014e72..0000000
+++ /dev/null
@@ -1,1753 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-#include <stddef.h>
-
-#ifdef WIN32
-#include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
-#else
-#ifdef HAVE_EXPAT_CONFIG_H
-#include <expat_config.h>
-#endif
-#endif /* ndef WIN32 */
-
-#include "expat_external.h"
-#include "internal.h"
-#include "xmltok.h"
-#include "nametab.h"
-
-#ifdef XML_DTD
-#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok)
-#else
-#define IGNORE_SECTION_TOK_VTABLE /* as nothing */
-#endif
-
-#define VTABLE1 \
-  { PREFIX(prologTok), PREFIX(contentTok), \
-    PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \
-  { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
-  PREFIX(sameName), \
-  PREFIX(nameMatchesAscii), \
-  PREFIX(nameLength), \
-  PREFIX(skipS), \
-  PREFIX(getAtts), \
-  PREFIX(charRefNumber), \
-  PREFIX(predefinedEntityName), \
-  PREFIX(updatePosition), \
-  PREFIX(isPublicId)
-
-#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
-
-#define UCS2_GET_NAMING(pages, hi, lo) \
-   (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1u << ((lo) & 0x1F)))
-
-/* A 2 byte UTF-8 representation splits the characters 11 bits between
-   the bottom 5 and 6 bits of the bytes.  We need 8 bits to index into
-   pages, 3 bits to add to that index and 5 bits to generate the mask.
-*/
-#define UTF8_GET_NAMING2(pages, byte) \
-    (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
-                      + ((((byte)[0]) & 3) << 1) \
-                      + ((((byte)[1]) >> 5) & 1)] \
-         & (1u << (((byte)[1]) & 0x1F)))
-
-/* A 3 byte UTF-8 representation splits the characters 16 bits between
-   the bottom 4, 6 and 6 bits of the bytes.  We need 8 bits to index
-   into pages, 3 bits to add to that index and 5 bits to generate the
-   mask.
-*/
-#define UTF8_GET_NAMING3(pages, byte) \
-  (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \
-                             + ((((byte)[1]) >> 2) & 0xF)] \
-                       << 3) \
-                      + ((((byte)[1]) & 3) << 1) \
-                      + ((((byte)[2]) >> 5) & 1)] \
-         & (1u << (((byte)[2]) & 0x1F)))
-
-#define UTF8_GET_NAMING(pages, p, n) \
-  ((n) == 2 \
-  ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
-  : ((n) == 3 \
-     ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \
-     : 0))
-
-/* Detection of invalid UTF-8 sequences is based on Table 3.1B
-   of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
-   with the additional restriction of not allowing the Unicode
-   code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE).
-   Implementation details:
-     (A & 0x80) == 0     means A < 0x80
-   and
-     (A & 0xC0) == 0xC0  means A > 0xBF
-*/
-
-#define UTF8_INVALID2(p) \
-  ((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0)
-
-#define UTF8_INVALID3(p) \
-  (((p)[2] & 0x80) == 0 \
-  || \
-  ((*p) == 0xEF && (p)[1] == 0xBF \
-    ? \
-    (p)[2] > 0xBD \
-    : \
-    ((p)[2] & 0xC0) == 0xC0) \
-  || \
-  ((*p) == 0xE0 \
-    ? \
-    (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \
-    : \
-    ((p)[1] & 0x80) == 0 \
-    || \
-    ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0)))
-
-#define UTF8_INVALID4(p) \
-  (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 \
-  || \
-  ((p)[2] & 0x80) == 0 || ((p)[2] & 0xC0) == 0xC0 \
-  || \
-  ((*p) == 0xF0 \
-    ? \
-    (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \
-    : \
-    ((p)[1] & 0x80) == 0 \
-    || \
-    ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0)))
-
-static int PTRFASTCALL
-isNever(const ENCODING *UNUSED_P(enc), const char *UNUSED_P(p))
-{
-  return 0;
-}
-
-static int PTRFASTCALL
-utf8_isName2(const ENCODING *UNUSED_P(enc), const char *p)
-{
-  return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
-}
-
-static int PTRFASTCALL
-utf8_isName3(const ENCODING *UNUSED_P(enc), const char *p)
-{
-  return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
-}
-
-#define utf8_isName4 isNever
-
-static int PTRFASTCALL
-utf8_isNmstrt2(const ENCODING *UNUSED_P(enc), const char *p)
-{
-  return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
-}
-
-static int PTRFASTCALL
-utf8_isNmstrt3(const ENCODING *UNUSED_P(enc), const char *p)
-{
-  return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
-}
-
-#define utf8_isNmstrt4 isNever
-
-static int PTRFASTCALL
-utf8_isInvalid2(const ENCODING *UNUSED_P(enc), const char *p)
-{
-  return UTF8_INVALID2((const unsigned char *)p);
-}
-
-static int PTRFASTCALL
-utf8_isInvalid3(const ENCODING *UNUSED_P(enc), const char *p)
-{
-  return UTF8_INVALID3((const unsigned char *)p);
-}
-
-static int PTRFASTCALL
-utf8_isInvalid4(const ENCODING *UNUSED_P(enc), const char *p)
-{
-  return UTF8_INVALID4((const unsigned char *)p);
-}
-
-struct normal_encoding {
-  ENCODING enc;
-  unsigned char type[256];
-#ifdef XML_MIN_SIZE
-  int (PTRFASTCALL *byteType)(const ENCODING *, const char *);
-  int (PTRFASTCALL *isNameMin)(const ENCODING *, const char *);
-  int (PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *);
-  int (PTRFASTCALL *byteToAscii)(const ENCODING *, const char *);
-  int (PTRCALL *charMatches)(const ENCODING *, const char *, int);
-#endif /* XML_MIN_SIZE */
-  int (PTRFASTCALL *isName2)(const ENCODING *, const char *);
-  int (PTRFASTCALL *isName3)(const ENCODING *, const char *);
-  int (PTRFASTCALL *isName4)(const ENCODING *, const char *);
-  int (PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *);
-  int (PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *);
-  int (PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *);
-  int (PTRFASTCALL *isInvalid2)(const ENCODING *, const char *);
-  int (PTRFASTCALL *isInvalid3)(const ENCODING *, const char *);
-  int (PTRFASTCALL *isInvalid4)(const ENCODING *, const char *);
-};
-
-#define AS_NORMAL_ENCODING(enc)   ((const struct normal_encoding *) (enc))
-
-#ifdef XML_MIN_SIZE
-
-#define STANDARD_VTABLE(E) \
- E ## byteType, \
- E ## isNameMin, \
- E ## isNmstrtMin, \
- E ## byteToAscii, \
- E ## charMatches,
-
-#else
-
-#define STANDARD_VTABLE(E) /* as nothing */
-
-#endif
-
-#define NORMAL_VTABLE(E) \
- E ## isName2, \
- E ## isName3, \
- E ## isName4, \
- E ## isNmstrt2, \
- E ## isNmstrt3, \
- E ## isNmstrt4, \
- E ## isInvalid2, \
- E ## isInvalid3, \
- E ## isInvalid4
-
-#define NULL_VTABLE \
- /* isName2 */ NULL, \
- /* isName3 */ NULL, \
- /* isName4 */ NULL, \
- /* isNmstrt2 */ NULL, \
- /* isNmstrt3 */ NULL, \
- /* isNmstrt4 */ NULL, \
- /* isInvalid2 */ NULL, \
- /* isInvalid3 */ NULL, \
- /* isInvalid4 */ NULL
-
-static int FASTCALL checkCharRefNumber(int);
-
-#include "xmltok_impl.h"
-#include "ascii.h"
-
-#ifdef XML_MIN_SIZE
-#define sb_isNameMin isNever
-#define sb_isNmstrtMin isNever
-#endif
-
-#ifdef XML_MIN_SIZE
-#define MINBPC(enc) ((enc)->minBytesPerChar)
-#else
-/* minimum bytes per character */
-#define MINBPC(enc) 1
-#endif
-
-#define SB_BYTE_TYPE(enc, p) \
-  (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
-
-#ifdef XML_MIN_SIZE
-static int PTRFASTCALL
-sb_byteType(const ENCODING *enc, const char *p)
-{
-  return SB_BYTE_TYPE(enc, p);
-}
-#define BYTE_TYPE(enc, p) \
- (AS_NORMAL_ENCODING(enc)->byteType(enc, p))
-#else
-#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
-#endif
-
-#ifdef XML_MIN_SIZE
-#define BYTE_TO_ASCII(enc, p) \
- (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p))
-static int PTRFASTCALL
-sb_byteToAscii(const ENCODING *enc, const char *p)
-{
-  return *p;
-}
-#else
-#define BYTE_TO_ASCII(enc, p) (*(p))
-#endif
-
-#define IS_NAME_CHAR(enc, p, n) \
- (AS_NORMAL_ENCODING(enc)->isName ## n(enc, p))
-#define IS_NMSTRT_CHAR(enc, p, n) \
- (AS_NORMAL_ENCODING(enc)->isNmstrt ## n(enc, p))
-#define IS_INVALID_CHAR(enc, p, n) \
- (AS_NORMAL_ENCODING(enc)->isInvalid ## n(enc, p))
-
-#ifdef XML_MIN_SIZE
-#define IS_NAME_CHAR_MINBPC(enc, p) \
- (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p))
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) \
- (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p))
-#else
-#define IS_NAME_CHAR_MINBPC(enc, p) (0)
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
-#endif
-
-#ifdef XML_MIN_SIZE
-#define CHAR_MATCHES(enc, p, c) \
- (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c))
-static int PTRCALL
-sb_charMatches(const ENCODING *enc, const char *p, int c)
-{
-  return *p == c;
-}
-#else
-/* c is an ASCII character */
-#define CHAR_MATCHES(enc, p, c) (*(p) == c)
-#endif
-
-#define PREFIX(ident) normal_ ## ident
-#define XML_TOK_IMPL_C
-#include "xmltok_impl.c"
-#undef XML_TOK_IMPL_C
-
-#undef MINBPC
-#undef BYTE_TYPE
-#undef BYTE_TO_ASCII
-#undef CHAR_MATCHES
-#undef IS_NAME_CHAR
-#undef IS_NAME_CHAR_MINBPC
-#undef IS_NMSTRT_CHAR
-#undef IS_NMSTRT_CHAR_MINBPC
-#undef IS_INVALID_CHAR
-
-enum {  /* UTF8_cvalN is value of masked first byte of N byte sequence */
-  UTF8_cval1 = 0x00,
-  UTF8_cval2 = 0xc0,
-  UTF8_cval3 = 0xe0,
-  UTF8_cval4 = 0xf0
-};
-
-void
-align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef)
-{
-  const char * fromLim = *fromLimRef;
-  size_t walked = 0;
-  for (; fromLim > from; fromLim--, walked++) {
-    const unsigned char prev = (unsigned char)fromLim[-1];
-    if ((prev & 0xf8u) == 0xf0u) { /* 4-byte character, lead by 0b11110xxx byte */
-      if (walked + 1 >= 4) {
-        fromLim += 4 - 1;
-        break;
-      } else {
-        walked = 0;
-      }
-    } else if ((prev & 0xf0u) == 0xe0u) { /* 3-byte character, lead by 0b1110xxxx byte */
-      if (walked + 1 >= 3) {
-        fromLim += 3 - 1;
-        break;
-      } else {
-        walked = 0;
-      }
-    } else if ((prev & 0xe0u) == 0xc0u) { /* 2-byte character, lead by 0b110xxxxx byte */
-      if (walked + 1 >= 2) {
-        fromLim += 2 - 1;
-        break;
-      } else {
-        walked = 0;
-      }
-    } else if ((prev & 0x80u) == 0x00u) { /* 1-byte character, matching 0b0xxxxxxx */
-      break;
-    }
-  }
-  *fromLimRef = fromLim;
-}
-
-static enum XML_Convert_Result PTRCALL
-utf8_toUtf8(const ENCODING *UNUSED_P(enc),
-            const char **fromP, const char *fromLim,
-            char **toP, const char *toLim)
-{
-  enum XML_Convert_Result res = XML_CONVERT_COMPLETED;
-  char *to;
-  const char *from;
-  if (fromLim - *fromP > toLim - *toP) {
-    /* Avoid copying partial characters. */
-    res = XML_CONVERT_OUTPUT_EXHAUSTED;
-    fromLim = *fromP + (toLim - *toP);
-    align_limit_to_full_utf8_characters(*fromP, &fromLim);
-  }
-  for (to = *toP, from = *fromP; (from < fromLim) && (to < toLim); from++, to++)
-    *to = *from;
-  *fromP = from;
-  *toP = to;
-
-  if ((to == toLim) && (from < fromLim))
-    return XML_CONVERT_OUTPUT_EXHAUSTED;
-  else
-    return res;
-}
-
-static enum XML_Convert_Result PTRCALL
-utf8_toUtf16(const ENCODING *enc,
-             const char **fromP, const char *fromLim,
-             unsigned short **toP, const unsigned short *toLim)
-{
-  enum XML_Convert_Result res = XML_CONVERT_COMPLETED;
-  unsigned short *to = *toP;
-  const char *from = *fromP;
-  while (from < fromLim && to < toLim) {
-    switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
-    case BT_LEAD2:
-      if (fromLim - from < 2) {
-        res = XML_CONVERT_INPUT_INCOMPLETE;
-        goto after;
-      }
-      *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f));
-      from += 2;
-      break;
-    case BT_LEAD3:
-      if (fromLim - from < 3) {
-        res = XML_CONVERT_INPUT_INCOMPLETE;
-        goto after;
-      }
-      *to++ = (unsigned short)(((from[0] & 0xf) << 12)
-                               | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f));
-      from += 3;
-      break;
-    case BT_LEAD4:
-      {
-        unsigned long n;
-        if (toLim - to < 2) {
-          res = XML_CONVERT_OUTPUT_EXHAUSTED;
-          goto after;
-        }
-        if (fromLim - from < 4) {
-          res = XML_CONVERT_INPUT_INCOMPLETE;
-          goto after;
-        }
-        n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12)
-            | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
-        n -= 0x10000;
-        to[0] = (unsigned short)((n >> 10) | 0xD800);
-        to[1] = (unsigned short)((n & 0x3FF) | 0xDC00);
-        to += 2;
-        from += 4;
-      }
-      break;
-    default:
-      *to++ = *from++;
-      break;
-    }
-  }
-  if (from < fromLim)
-    res = XML_CONVERT_OUTPUT_EXHAUSTED;
-after:
-  *fromP = from;
-  *toP = to;
-  return res;
-}
-
-#ifdef XML_NS
-static const struct normal_encoding utf8_encoding_ns = {
-  { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
-  {
-#include "asciitab.h"
-#include "utf8tab.h"
-  },
-  STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
-#endif
-
-static const struct normal_encoding utf8_encoding = {
-  { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
-  {
-#define BT_COLON BT_NMSTRT
-#include "asciitab.h"
-#undef BT_COLON
-#include "utf8tab.h"
-  },
-  STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
-
-#ifdef XML_NS
-
-static const struct normal_encoding internal_utf8_encoding_ns = {
-  { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
-  {
-#include "iasciitab.h"
-#include "utf8tab.h"
-  },
-  STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
-
-#endif
-
-static const struct normal_encoding internal_utf8_encoding = {
-  { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
-  {
-#define BT_COLON BT_NMSTRT
-#include "iasciitab.h"
-#undef BT_COLON
-#include "utf8tab.h"
-  },
-  STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
-
-static enum XML_Convert_Result PTRCALL
-latin1_toUtf8(const ENCODING *UNUSED_P(enc),
-              const char **fromP, const char *fromLim,
-              char **toP, const char *toLim)
-{
-  for (;;) {
-    unsigned char c;
-    if (*fromP == fromLim)
-      return XML_CONVERT_COMPLETED;
-    c = (unsigned char)**fromP;
-    if (c & 0x80) {
-      if (toLim - *toP < 2)
-        return XML_CONVERT_OUTPUT_EXHAUSTED;
-      *(*toP)++ = (char)((c >> 6) | UTF8_cval2);
-      *(*toP)++ = (char)((c & 0x3f) | 0x80);
-      (*fromP)++;
-    }
-    else {
-      if (*toP == toLim)
-        return XML_CONVERT_OUTPUT_EXHAUSTED;
-      *(*toP)++ = *(*fromP)++;
-    }
-  }
-}
-
-static enum XML_Convert_Result PTRCALL
-latin1_toUtf16(const ENCODING *UNUSED_P(enc),
-               const char **fromP, const char *fromLim,
-               unsigned short **toP, const unsigned short *toLim)
-{
-  while (*fromP < fromLim && *toP < toLim)
-    *(*toP)++ = (unsigned char)*(*fromP)++;
-
-  if ((*toP == toLim) && (*fromP < fromLim))
-    return XML_CONVERT_OUTPUT_EXHAUSTED;
-  else
-    return XML_CONVERT_COMPLETED;
-}
-
-#ifdef XML_NS
-
-static const struct normal_encoding latin1_encoding_ns = {
-  { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
-  {
-#include "asciitab.h"
-#include "latin1tab.h"
-  },
-  STANDARD_VTABLE(sb_) NULL_VTABLE
-};
-
-#endif
-
-static const struct normal_encoding latin1_encoding = {
-  { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
-  {
-#define BT_COLON BT_NMSTRT
-#include "asciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
-  },
-  STANDARD_VTABLE(sb_) NULL_VTABLE
-};
-
-static enum XML_Convert_Result PTRCALL
-ascii_toUtf8(const ENCODING *UNUSED_P(enc),
-             const char **fromP, const char *fromLim,
-             char **toP, const char *toLim)
-{
-  while (*fromP < fromLim && *toP < toLim)
-    *(*toP)++ = *(*fromP)++;
-
-  if ((*toP == toLim) && (*fromP < fromLim))
-    return XML_CONVERT_OUTPUT_EXHAUSTED;
-  else
-    return XML_CONVERT_COMPLETED;
-}
-
-#ifdef XML_NS
-
-static const struct normal_encoding ascii_encoding_ns = {
-  { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
-  {
-#include "asciitab.h"
-/* BT_NONXML == 0 */
-  },
-  STANDARD_VTABLE(sb_) NULL_VTABLE
-};
-
-#endif
-
-static const struct normal_encoding ascii_encoding = {
-  { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
-  {
-#define BT_COLON BT_NMSTRT
-#include "asciitab.h"
-#undef BT_COLON
-/* BT_NONXML == 0 */
-  },
-  STANDARD_VTABLE(sb_) NULL_VTABLE
-};
-
-static int PTRFASTCALL
-unicode_byte_type(char hi, char lo)
-{
-  switch ((unsigned char)hi) {
-  case 0xD8: case 0xD9: case 0xDA: case 0xDB:
-    return BT_LEAD4;
-  case 0xDC: case 0xDD: case 0xDE: case 0xDF:
-    return BT_TRAIL;
-  case 0xFF:
-    switch ((unsigned char)lo) {
-    case 0xFF:
-    case 0xFE:
-      return BT_NONXML;
-    }
-    break;
-  }
-  return BT_NONASCII;
-}
-
-#define DEFINE_UTF16_TO_UTF8(E) \
-static enum XML_Convert_Result  PTRCALL \
-E ## toUtf8(const ENCODING *UNUSED_P(enc), \
-            const char **fromP, const char *fromLim, \
-            char **toP, const char *toLim) \
-{ \
-  const char *from = *fromP; \
-  fromLim = from + (((fromLim - from) >> 1) << 1);  /* shrink to even */ \
-  for (; from < fromLim; from += 2) { \
-    int plane; \
-    unsigned char lo2; \
-    unsigned char lo = GET_LO(from); \
-    unsigned char hi = GET_HI(from); \
-    switch (hi) { \
-    case 0: \
-      if (lo < 0x80) { \
-        if (*toP == toLim) { \
-          *fromP = from; \
-          return XML_CONVERT_OUTPUT_EXHAUSTED; \
-        } \
-        *(*toP)++ = lo; \
-        break; \
-      } \
-      /* fall through */ \
-    case 0x1: case 0x2: case 0x3: \
-    case 0x4: case 0x5: case 0x6: case 0x7: \
-      if (toLim -  *toP < 2) { \
-        *fromP = from; \
-        return XML_CONVERT_OUTPUT_EXHAUSTED; \
-      } \
-      *(*toP)++ = ((lo >> 6) | (hi << 2) |  UTF8_cval2); \
-      *(*toP)++ = ((lo & 0x3f) | 0x80); \
-      break; \
-    default: \
-      if (toLim -  *toP < 3)  { \
-        *fromP = from; \
-        return XML_CONVERT_OUTPUT_EXHAUSTED; \
-      } \
-      /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
-      *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
-      *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \
-      *(*toP)++ = ((lo & 0x3f) | 0x80); \
-      break; \
-    case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
-      if (toLim -  *toP < 4) { \
-        *fromP = from; \
-        return XML_CONVERT_OUTPUT_EXHAUSTED; \
-      } \
-      if (fromLim - from < 4) { \
-        *fromP = from; \
-        return XML_CONVERT_INPUT_INCOMPLETE; \
-      } \
-      plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
-      *(*toP)++ = ((plane >> 2) | UTF8_cval4); \
-      *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
-      from += 2; \
-      lo2 = GET_LO(from); \
-      *(*toP)++ = (((lo & 0x3) << 4) \
-                   | ((GET_HI(from) & 0x3) << 2) \
-                   | (lo2 >> 6) \
-                   | 0x80); \
-      *(*toP)++ = ((lo2 & 0x3f) | 0x80); \
-      break; \
-    } \
-  } \
-  *fromP = from; \
-  if (from < fromLim) \
-    return XML_CONVERT_INPUT_INCOMPLETE; \
-  else \
-    return XML_CONVERT_COMPLETED; \
-}
-
-#define DEFINE_UTF16_TO_UTF16(E) \
-static enum XML_Convert_Result  PTRCALL \
-E ## toUtf16(const ENCODING *UNUSED_P(enc), \
-             const char **fromP, const char *fromLim, \
-             unsigned short **toP, const unsigned short *toLim) \
-{ \
-  enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \
-  fromLim = *fromP + (((fromLim - *fromP) >> 1) << 1);  /* shrink to even */ \
-  /* Avoid copying first half only of surrogate */ \
-  if (fromLim - *fromP > ((toLim - *toP) << 1) \
-      && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) { \
-    fromLim -= 2; \
-    res = XML_CONVERT_INPUT_INCOMPLETE; \
-  } \
-  for (; *fromP < fromLim && *toP < toLim; *fromP += 2) \
-    *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
-  if ((*toP == toLim) && (*fromP < fromLim)) \
-    return XML_CONVERT_OUTPUT_EXHAUSTED; \
-  else \
-    return res; \
-}
-
-#define SET2(ptr, ch) \
-  (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8)))
-#define GET_LO(ptr) ((unsigned char)(ptr)[0])
-#define GET_HI(ptr) ((unsigned char)(ptr)[1])
-
-DEFINE_UTF16_TO_UTF8(little2_)
-DEFINE_UTF16_TO_UTF16(little2_)
-
-#undef SET2
-#undef GET_LO
-#undef GET_HI
-
-#define SET2(ptr, ch) \
-  (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF)))
-#define GET_LO(ptr) ((unsigned char)(ptr)[1])
-#define GET_HI(ptr) ((unsigned char)(ptr)[0])
-
-DEFINE_UTF16_TO_UTF8(big2_)
-DEFINE_UTF16_TO_UTF16(big2_)
-
-#undef SET2
-#undef GET_LO
-#undef GET_HI
-
-#define LITTLE2_BYTE_TYPE(enc, p) \
- ((p)[1] == 0 \
-  ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \
-  : unicode_byte_type((p)[1], (p)[0]))
-#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1)
-#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c)
-#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \
-  UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
-#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
-  UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0])
-
-#ifdef XML_MIN_SIZE
-
-static int PTRFASTCALL
-little2_byteType(const ENCODING *enc, const char *p)
-{
-  return LITTLE2_BYTE_TYPE(enc, p);
-}
-
-static int PTRFASTCALL
-little2_byteToAscii(const ENCODING *enc, const char *p)
-{
-  return LITTLE2_BYTE_TO_ASCII(enc, p);
-}
-
-static int PTRCALL
-little2_charMatches(const ENCODING *enc, const char *p, int c)
-{
-  return LITTLE2_CHAR_MATCHES(enc, p, c);
-}
-
-static int PTRFASTCALL
-little2_isNameMin(const ENCODING *enc, const char *p)
-{
-  return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p);
-}
-
-static int PTRFASTCALL
-little2_isNmstrtMin(const ENCODING *enc, const char *p)
-{
-  return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p);
-}
-
-#undef VTABLE
-#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16
-
-#else /* not XML_MIN_SIZE */
-
-#undef PREFIX
-#define PREFIX(ident) little2_ ## ident
-#define MINBPC(enc) 2
-/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
-#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
-#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p)
-#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c)
-#define IS_NAME_CHAR(enc, p, n) 0
-#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p)
-#define IS_NMSTRT_CHAR(enc, p, n) (0)
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p)
-
-#define XML_TOK_IMPL_C
-#include "xmltok_impl.c"
-#undef XML_TOK_IMPL_C
-
-#undef MINBPC
-#undef BYTE_TYPE
-#undef BYTE_TO_ASCII
-#undef CHAR_MATCHES
-#undef IS_NAME_CHAR
-#undef IS_NAME_CHAR_MINBPC
-#undef IS_NMSTRT_CHAR
-#undef IS_NMSTRT_CHAR_MINBPC
-#undef IS_INVALID_CHAR
-
-#endif /* not XML_MIN_SIZE */
-
-#ifdef XML_NS
-
-static const struct normal_encoding little2_encoding_ns = {
-  { VTABLE, 2, 0,
-#if BYTEORDER == 1234
-    1
-#else
-    0
-#endif
-  },
-  {
-#include "asciitab.h"
-#include "latin1tab.h"
-  },
-  STANDARD_VTABLE(little2_) NULL_VTABLE
-};
-
-#endif
-
-static const struct normal_encoding little2_encoding = {
-  { VTABLE, 2, 0,
-#if BYTEORDER == 1234
-    1
-#else
-    0
-#endif
-  },
-  {
-#define BT_COLON BT_NMSTRT
-#include "asciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
-  },
-  STANDARD_VTABLE(little2_) NULL_VTABLE
-};
-
-#if BYTEORDER != 4321
-
-#ifdef XML_NS
-
-static const struct normal_encoding internal_little2_encoding_ns = {
-  { VTABLE, 2, 0, 1 },
-  {
-#include "iasciitab.h"
-#include "latin1tab.h"
-  },
-  STANDARD_VTABLE(little2_) NULL_VTABLE
-};
-
-#endif
-
-static const struct normal_encoding internal_little2_encoding = {
-  { VTABLE, 2, 0, 1 },
-  {
-#define BT_COLON BT_NMSTRT
-#include "iasciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
-  },
-  STANDARD_VTABLE(little2_) NULL_VTABLE
-};
-
-#endif
-
-
-#define BIG2_BYTE_TYPE(enc, p) \
- ((p)[0] == 0 \
-  ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \
-  : unicode_byte_type((p)[0], (p)[1]))
-#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1)
-#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c)
-#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \
-  UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
-#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
-  UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1])
-
-#ifdef XML_MIN_SIZE
-
-static int PTRFASTCALL
-big2_byteType(const ENCODING *enc, const char *p)
-{
-  return BIG2_BYTE_TYPE(enc, p);
-}
-
-static int PTRFASTCALL
-big2_byteToAscii(const ENCODING *enc, const char *p)
-{
-  return BIG2_BYTE_TO_ASCII(enc, p);
-}
-
-static int PTRCALL
-big2_charMatches(const ENCODING *enc, const char *p, int c)
-{
-  return BIG2_CHAR_MATCHES(enc, p, c);
-}
-
-static int PTRFASTCALL
-big2_isNameMin(const ENCODING *enc, const char *p)
-{
-  return BIG2_IS_NAME_CHAR_MINBPC(enc, p);
-}
-
-static int PTRFASTCALL
-big2_isNmstrtMin(const ENCODING *enc, const char *p)
-{
-  return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p);
-}
-
-#undef VTABLE
-#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16
-
-#else /* not XML_MIN_SIZE */
-
-#undef PREFIX
-#define PREFIX(ident) big2_ ## ident
-#define MINBPC(enc) 2
-/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
-#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
-#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p)
-#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c)
-#define IS_NAME_CHAR(enc, p, n) 0
-#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p)
-#define IS_NMSTRT_CHAR(enc, p, n) (0)
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p)
-
-#define XML_TOK_IMPL_C
-#include "xmltok_impl.c"
-#undef XML_TOK_IMPL_C
-
-#undef MINBPC
-#undef BYTE_TYPE
-#undef BYTE_TO_ASCII
-#undef CHAR_MATCHES
-#undef IS_NAME_CHAR
-#undef IS_NAME_CHAR_MINBPC
-#undef IS_NMSTRT_CHAR
-#undef IS_NMSTRT_CHAR_MINBPC
-#undef IS_INVALID_CHAR
-
-#endif /* not XML_MIN_SIZE */
-
-#ifdef XML_NS
-
-static const struct normal_encoding big2_encoding_ns = {
-  { VTABLE, 2, 0,
-#if BYTEORDER == 4321
-  1
-#else
-  0
-#endif
-  },
-  {
-#include "asciitab.h"
-#include "latin1tab.h"
-  },
-  STANDARD_VTABLE(big2_) NULL_VTABLE
-};
-
-#endif
-
-static const struct normal_encoding big2_encoding = {
-  { VTABLE, 2, 0,
-#if BYTEORDER == 4321
-  1
-#else
-  0
-#endif
-  },
-  {
-#define BT_COLON BT_NMSTRT
-#include "asciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
-  },
-  STANDARD_VTABLE(big2_) NULL_VTABLE
-};
-
-#if BYTEORDER != 1234
-
-#ifdef XML_NS
-
-static const struct normal_encoding internal_big2_encoding_ns = {
-  { VTABLE, 2, 0, 1 },
-  {
-#include "iasciitab.h"
-#include "latin1tab.h"
-  },
-  STANDARD_VTABLE(big2_) NULL_VTABLE
-};
-
-#endif
-
-static const struct normal_encoding internal_big2_encoding = {
-  { VTABLE, 2, 0, 1 },
-  {
-#define BT_COLON BT_NMSTRT
-#include "iasciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
-  },
-  STANDARD_VTABLE(big2_) NULL_VTABLE
-};
-
-#endif
-
-#undef PREFIX
-
-static int FASTCALL
-streqci(const char *s1, const char *s2)
-{
-  for (;;) {
-    char c1 = *s1++;
-    char c2 = *s2++;
-    if (ASCII_a <= c1 && c1 <= ASCII_z)
-      c1 += ASCII_A - ASCII_a;
-    if (ASCII_a <= c2 && c2 <= ASCII_z)
-      c2 += ASCII_A - ASCII_a;
-    if (c1 != c2)
-      return 0;
-    if (!c1)
-      break;
-  }
-  return 1;
-}
-
-static void PTRCALL
-initUpdatePosition(const ENCODING *UNUSED_P(enc), const char *ptr,
-                   const char *end, POSITION *pos)
-{
-  normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
-}
-
-static int
-toAscii(const ENCODING *enc, const char *ptr, const char *end)
-{
-  char buf[1];
-  char *p = buf;
-  XmlUtf8Convert(enc, &ptr, end, &p, p + 1);
-  if (p == buf)
-    return -1;
-  else
-    return buf[0];
-}
-
-static int FASTCALL
-isSpace(int c)
-{
-  switch (c) {
-  case 0x20:
-  case 0xD:
-  case 0xA:
-  case 0x9:
-    return 1;
-  }
-  return 0;
-}
-
-/* Return 1 if there's just optional white space or there's an S
-   followed by name=val.
-*/
-static int
-parsePseudoAttribute(const ENCODING *enc,
-                     const char *ptr,
-                     const char *end,
-                     const char **namePtr,
-                     const char **nameEndPtr,
-                     const char **valPtr,
-                     const char **nextTokPtr)
-{
-  int c;
-  char open;
-  if (ptr == end) {
-    *namePtr = NULL;
-    return 1;
-  }
-  if (!isSpace(toAscii(enc, ptr, end))) {
-    *nextTokPtr = ptr;
-    return 0;
-  }
-  do {
-    ptr += enc->minBytesPerChar;
-  } while (isSpace(toAscii(enc, ptr, end)));
-  if (ptr == end) {
-    *namePtr = NULL;
-    return 1;
-  }
-  *namePtr = ptr;
-  for (;;) {
-    c = toAscii(enc, ptr, end);
-    if (c == -1) {
-      *nextTokPtr = ptr;
-      return 0;
-    }
-    if (c == ASCII_EQUALS) {
-      *nameEndPtr = ptr;
-      break;
-    }
-    if (isSpace(c)) {
-      *nameEndPtr = ptr;
-      do {
-        ptr += enc->minBytesPerChar;
-      } while (isSpace(c = toAscii(enc, ptr, end)));
-      if (c != ASCII_EQUALS) {
-        *nextTokPtr = ptr;
-        return 0;
-      }
-      break;
-    }
-    ptr += enc->minBytesPerChar;
-  }
-  if (ptr == *namePtr) {
-    *nextTokPtr = ptr;
-    return 0;
-  }
-  ptr += enc->minBytesPerChar;
-  c = toAscii(enc, ptr, end);
-  while (isSpace(c)) {
-    ptr += enc->minBytesPerChar;
-    c = toAscii(enc, ptr, end);
-  }
-  if (c != ASCII_QUOT && c != ASCII_APOS) {
-    *nextTokPtr = ptr;
-    return 0;
-  }
-  open = (char)c;
-  ptr += enc->minBytesPerChar;
-  *valPtr = ptr;
-  for (;; ptr += enc->minBytesPerChar) {
-    c = toAscii(enc, ptr, end);
-    if (c == open)
-      break;
-    if (!(ASCII_a <= c && c <= ASCII_z)
-        && !(ASCII_A <= c && c <= ASCII_Z)
-        && !(ASCII_0 <= c && c <= ASCII_9)
-        && c != ASCII_PERIOD
-        && c != ASCII_MINUS
-        && c != ASCII_UNDERSCORE) {
-      *nextTokPtr = ptr;
-      return 0;
-    }
-  }
-  *nextTokPtr = ptr + enc->minBytesPerChar;
-  return 1;
-}
-
-static const char KW_version[] = {
-  ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0'
-};
-
-static const char KW_encoding[] = {
-  ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0'
-};
-
-static const char KW_standalone[] = {
-  ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o,
-  ASCII_n, ASCII_e, '\0'
-};
-
-static const char KW_yes[] = {
-  ASCII_y, ASCII_e, ASCII_s,  '\0'
-};
-
-static const char KW_no[] = {
-  ASCII_n, ASCII_o,  '\0'
-};
-
-static int
-doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
-                                                 const char *,
-                                                 const char *),
-               int isGeneralTextEntity,
-               const ENCODING *enc,
-               const char *ptr,
-               const char *end,
-               const char **badPtr,
-               const char **versionPtr,
-               const char **versionEndPtr,
-               const char **encodingName,
-               const ENCODING **encoding,
-               int *standalone)
-{
-  const char *val = NULL;
-  const char *name = NULL;
-  const char *nameEnd = NULL;
-  ptr += 5 * enc->minBytesPerChar;
-  end -= 2 * enc->minBytesPerChar;
-  if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)
-      || !name) {
-    *badPtr = ptr;
-    return 0;
-  }
-  if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) {
-    if (!isGeneralTextEntity) {
-      *badPtr = name;
-      return 0;
-    }
-  }
-  else {
-    if (versionPtr)
-      *versionPtr = val;
-    if (versionEndPtr)
-      *versionEndPtr = ptr;
-    if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
-      *badPtr = ptr;
-      return 0;
-    }
-    if (!name) {
-      if (isGeneralTextEntity) {
-        /* a TextDecl must have an EncodingDecl */
-        *badPtr = ptr;
-        return 0;
-      }
-      return 1;
-    }
-  }
-  if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) {
-    int c = toAscii(enc, val, end);
-    if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) {
-      *badPtr = val;
-      return 0;
-    }
-    if (encodingName)
-      *encodingName = val;
-    if (encoding)
-      *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar);
-    if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
-      *badPtr = ptr;
-      return 0;
-    }
-    if (!name)
-      return 1;
-  }
-  if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone)
-      || isGeneralTextEntity) {
-    *badPtr = name;
-    return 0;
-  }
-  if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) {
-    if (standalone)
-      *standalone = 1;
-  }
-  else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) {
-    if (standalone)
-      *standalone = 0;
-  }
-  else {
-    *badPtr = val;
-    return 0;
-  }
-  while (isSpace(toAscii(enc, ptr, end)))
-    ptr += enc->minBytesPerChar;
-  if (ptr != end) {
-    *badPtr = ptr;
-    return 0;
-  }
-  return 1;
-}
-
-static int FASTCALL
-checkCharRefNumber(int result)
-{
-  switch (result >> 8) {
-  case 0xD8: case 0xD9: case 0xDA: case 0xDB:
-  case 0xDC: case 0xDD: case 0xDE: case 0xDF:
-    return -1;
-  case 0:
-    if (latin1_encoding.type[result] == BT_NONXML)
-      return -1;
-    break;
-  case 0xFF:
-    if (result == 0xFFFE || result == 0xFFFF)
-      return -1;
-    break;
-  }
-  return result;
-}
-
-int FASTCALL
-XmlUtf8Encode(int c, char *buf)
-{
-  enum {
-    /* minN is minimum legal resulting value for N byte sequence */
-    min2 = 0x80,
-    min3 = 0x800,
-    min4 = 0x10000
-  };
-
-  if (c < 0)
-    return 0;
-  if (c < min2) {
-    buf[0] = (char)(c | UTF8_cval1);
-    return 1;
-  }
-  if (c < min3) {
-    buf[0] = (char)((c >> 6) | UTF8_cval2);
-    buf[1] = (char)((c & 0x3f) | 0x80);
-    return 2;
-  }
-  if (c < min4) {
-    buf[0] = (char)((c >> 12) | UTF8_cval3);
-    buf[1] = (char)(((c >> 6) & 0x3f) | 0x80);
-    buf[2] = (char)((c & 0x3f) | 0x80);
-    return 3;
-  }
-  if (c < 0x110000) {
-    buf[0] = (char)((c >> 18) | UTF8_cval4);
-    buf[1] = (char)(((c >> 12) & 0x3f) | 0x80);
-    buf[2] = (char)(((c >> 6) & 0x3f) | 0x80);
-    buf[3] = (char)((c & 0x3f) | 0x80);
-    return 4;
-  }
-  return 0;
-}
-
-int FASTCALL
-XmlUtf16Encode(int charNum, unsigned short *buf)
-{
-  if (charNum < 0)
-    return 0;
-  if (charNum < 0x10000) {
-    buf[0] = (unsigned short)charNum;
-    return 1;
-  }
-  if (charNum < 0x110000) {
-    charNum -= 0x10000;
-    buf[0] = (unsigned short)((charNum >> 10) + 0xD800);
-    buf[1] = (unsigned short)((charNum & 0x3FF) + 0xDC00);
-    return 2;
-  }
-  return 0;
-}
-
-struct unknown_encoding {
-  struct normal_encoding normal;
-  CONVERTER convert;
-  void *userData;
-  unsigned short utf16[256];
-  char utf8[256][4];
-};
-
-#define AS_UNKNOWN_ENCODING(enc)  ((const struct unknown_encoding *) (enc))
-
-int
-XmlSizeOfUnknownEncoding(void)
-{
-  return sizeof(struct unknown_encoding);
-}
-
-static int PTRFASTCALL
-unknown_isName(const ENCODING *enc, const char *p)
-{
-  const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
-  int c = uenc->convert(uenc->userData, p);
-  if (c & ~0xFFFF)
-    return 0;
-  return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF);
-}
-
-static int PTRFASTCALL
-unknown_isNmstrt(const ENCODING *enc, const char *p)
-{
-  const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
-  int c = uenc->convert(uenc->userData, p);
-  if (c & ~0xFFFF)
-    return 0;
-  return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF);
-}
-
-static int PTRFASTCALL
-unknown_isInvalid(const ENCODING *enc, const char *p)
-{
-  const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
-  int c = uenc->convert(uenc->userData, p);
-  return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
-}
-
-static enum XML_Convert_Result PTRCALL
-unknown_toUtf8(const ENCODING *enc,
-               const char **fromP, const char *fromLim,
-               char **toP, const char *toLim)
-{
-  const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
-  char buf[XML_UTF8_ENCODE_MAX];
-  for (;;) {
-    const char *utf8;
-    int n;
-    if (*fromP == fromLim)
-      return XML_CONVERT_COMPLETED;
-    utf8 = uenc->utf8[(unsigned char)**fromP];
-    n = *utf8++;
-    if (n == 0) {
-      int c = uenc->convert(uenc->userData, *fromP);
-      n = XmlUtf8Encode(c, buf);
-      if (n > toLim - *toP)
-        return XML_CONVERT_OUTPUT_EXHAUSTED;
-      utf8 = buf;
-      *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
-                 - (BT_LEAD2 - 2));
-    }
-    else {
-      if (n > toLim - *toP)
-        return XML_CONVERT_OUTPUT_EXHAUSTED;
-      (*fromP)++;
-    }
-    do {
-      *(*toP)++ = *utf8++;
-    } while (--n != 0);
-  }
-}
-
-static enum XML_Convert_Result PTRCALL
-unknown_toUtf16(const ENCODING *enc,
-                const char **fromP, const char *fromLim,
-                unsigned short **toP, const unsigned short *toLim)
-{
-  const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
-  while (*fromP < fromLim && *toP < toLim) {
-    unsigned short c = uenc->utf16[(unsigned char)**fromP];
-    if (c == 0) {
-      c = (unsigned short)
-          uenc->convert(uenc->userData, *fromP);
-      *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
-                 - (BT_LEAD2 - 2));
-    }
-    else
-      (*fromP)++;
-    *(*toP)++ = c;
-  }
-
-  if ((*toP == toLim) && (*fromP < fromLim))
-    return XML_CONVERT_OUTPUT_EXHAUSTED;
-  else
-    return XML_CONVERT_COMPLETED;
-}
-
-ENCODING *
-XmlInitUnknownEncoding(void *mem,
-                       int *table,
-                       CONVERTER convert,
-                       void *userData)
-{
-  int i;
-  struct unknown_encoding *e = (struct unknown_encoding *)mem;
-  for (i = 0; i < (int)sizeof(struct normal_encoding); i++)
-    ((char *)mem)[i] = ((char *)&latin1_encoding)[i];
-  for (i = 0; i < 128; i++)
-    if (latin1_encoding.type[i] != BT_OTHER
-        && latin1_encoding.type[i] != BT_NONXML
-        && table[i] != i)
-      return 0;
-  for (i = 0; i < 256; i++) {
-    int c = table[i];
-    if (c == -1) {
-      e->normal.type[i] = BT_MALFORM;
-      /* This shouldn't really get used. */
-      e->utf16[i] = 0xFFFF;
-      e->utf8[i][0] = 1;
-      e->utf8[i][1] = 0;
-    }
-    else if (c < 0) {
-      if (c < -4)
-        return 0;
-      e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2));
-      e->utf8[i][0] = 0;
-      e->utf16[i] = 0;
-    }
-    else if (c < 0x80) {
-      if (latin1_encoding.type[c] != BT_OTHER
-          && latin1_encoding.type[c] != BT_NONXML
-          && c != i)
-        return 0;
-      e->normal.type[i] = latin1_encoding.type[c];
-      e->utf8[i][0] = 1;
-      e->utf8[i][1] = (char)c;
-      e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c);
-    }
-    else if (checkCharRefNumber(c) < 0) {
-      e->normal.type[i] = BT_NONXML;
-      /* This shouldn't really get used. */
-      e->utf16[i] = 0xFFFF;
-      e->utf8[i][0] = 1;
-      e->utf8[i][1] = 0;
-    }
-    else {
-      if (c > 0xFFFF)
-        return 0;
-      if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff))
-        e->normal.type[i] = BT_NMSTRT;
-      else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff))
-        e->normal.type[i] = BT_NAME;
-      else
-        e->normal.type[i] = BT_OTHER;
-      e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1);
-      e->utf16[i] = (unsigned short)c;
-    }
-  }
-  e->userData = userData;
-  e->convert = convert;
-  if (convert) {
-    e->normal.isName2 = unknown_isName;
-    e->normal.isName3 = unknown_isName;
-    e->normal.isName4 = unknown_isName;
-    e->normal.isNmstrt2 = unknown_isNmstrt;
-    e->normal.isNmstrt3 = unknown_isNmstrt;
-    e->normal.isNmstrt4 = unknown_isNmstrt;
-    e->normal.isInvalid2 = unknown_isInvalid;
-    e->normal.isInvalid3 = unknown_isInvalid;
-    e->normal.isInvalid4 = unknown_isInvalid;
-  }
-  e->normal.enc.utf8Convert = unknown_toUtf8;
-  e->normal.enc.utf16Convert = unknown_toUtf16;
-  return &(e->normal.enc);
-}
-
-/* If this enumeration is changed, getEncodingIndex and encodings
-must also be changed. */
-enum {
-  UNKNOWN_ENC = -1,
-  ISO_8859_1_ENC = 0,
-  US_ASCII_ENC,
-  UTF_8_ENC,
-  UTF_16_ENC,
-  UTF_16BE_ENC,
-  UTF_16LE_ENC,
-  /* must match encodingNames up to here */
-  NO_ENC
-};
-
-static const char KW_ISO_8859_1[] = {
-  ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9,
-  ASCII_MINUS, ASCII_1, '\0'
-};
-static const char KW_US_ASCII[] = {
-  ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I,
-  '\0'
-};
-static const char KW_UTF_8[] =  {
-  ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0'
-};
-static const char KW_UTF_16[] = {
-  ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0'
-};
-static const char KW_UTF_16BE[] = {
-  ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E,
-  '\0'
-};
-static const char KW_UTF_16LE[] = {
-  ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E,
-  '\0'
-};
-
-static int FASTCALL
-getEncodingIndex(const char *name)
-{
-  static const char * const encodingNames[] = {
-    KW_ISO_8859_1,
-    KW_US_ASCII,
-    KW_UTF_8,
-    KW_UTF_16,
-    KW_UTF_16BE,
-    KW_UTF_16LE,
-  };
-  int i;
-  if (name == NULL)
-    return NO_ENC;
-  for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++)
-    if (streqci(name, encodingNames[i]))
-      return i;
-  return UNKNOWN_ENC;
-}
-
-/* For binary compatibility, we store the index of the encoding
-   specified at initialization in the isUtf16 member.
-*/
-
-#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16)
-#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i)
-
-/* This is what detects the encoding.  encodingTable maps from
-   encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of
-   the external (protocol) specified encoding; state is
-   XML_CONTENT_STATE if we're parsing an external text entity, and
-   XML_PROLOG_STATE otherwise.
-*/
-
-
-static int
-initScan(const ENCODING * const *encodingTable,
-         const INIT_ENCODING *enc,
-         int state,
-         const char *ptr,
-         const char *end,
-         const char **nextTokPtr)
-{
-  const ENCODING **encPtr;
-
-  if (ptr >= end)
-    return XML_TOK_NONE;
-  encPtr = enc->encPtr;
-  if (ptr + 1 == end) {
-    /* only a single byte available for auto-detection */
-#ifndef XML_DTD /* FIXME */
-    /* a well-formed document entity must have more than one byte */
-    if (state != XML_CONTENT_STATE)
-      return XML_TOK_PARTIAL;
-#endif
-    /* so we're parsing an external text entity... */
-    /* if UTF-16 was externally specified, then we need at least 2 bytes */
-    switch (INIT_ENC_INDEX(enc)) {
-    case UTF_16_ENC:
-    case UTF_16LE_ENC:
-    case UTF_16BE_ENC:
-      return XML_TOK_PARTIAL;
-    }
-    switch ((unsigned char)*ptr) {
-    case 0xFE:
-    case 0xFF:
-    case 0xEF: /* possibly first byte of UTF-8 BOM */
-      if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
-          && state == XML_CONTENT_STATE)
-        break;
-      /* fall through */
-    case 0x00:
-    case 0x3C:
-      return XML_TOK_PARTIAL;
-    }
-  }
-  else {
-    switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) {
-    case 0xFEFF:
-      if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
-          && state == XML_CONTENT_STATE)
-        break;
-      *nextTokPtr = ptr + 2;
-      *encPtr = encodingTable[UTF_16BE_ENC];
-      return XML_TOK_BOM;
-    /* 00 3C is handled in the default case */
-    case 0x3C00:
-      if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC
-           || INIT_ENC_INDEX(enc) == UTF_16_ENC)
-          && state == XML_CONTENT_STATE)
-        break;
-      *encPtr = encodingTable[UTF_16LE_ENC];
-      return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
-    case 0xFFFE:
-      if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
-          && state == XML_CONTENT_STATE)
-        break;
-      *nextTokPtr = ptr + 2;
-      *encPtr = encodingTable[UTF_16LE_ENC];
-      return XML_TOK_BOM;
-    case 0xEFBB:
-      /* Maybe a UTF-8 BOM (EF BB BF) */
-      /* If there's an explicitly specified (external) encoding
-         of ISO-8859-1 or some flavour of UTF-16
-         and this is an external text entity,
-         don't look for the BOM,
-         because it might be a legal data.
-      */
-      if (state == XML_CONTENT_STATE) {
-        int e = INIT_ENC_INDEX(enc);
-        if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC
-            || e == UTF_16LE_ENC || e == UTF_16_ENC)
-          break;
-      }
-      if (ptr + 2 == end)
-        return XML_TOK_PARTIAL;
-      if ((unsigned char)ptr[2] == 0xBF) {
-        *nextTokPtr = ptr + 3;
-        *encPtr = encodingTable[UTF_8_ENC];
-        return XML_TOK_BOM;
-      }
-      break;
-    default:
-      if (ptr[0] == '\0') {
-        /* 0 isn't a legal data character. Furthermore a document
-           entity can only start with ASCII characters.  So the only
-           way this can fail to be big-endian UTF-16 if it it's an
-           external parsed general entity that's labelled as
-           UTF-16LE.
-        */
-        if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC)
-          break;
-        *encPtr = encodingTable[UTF_16BE_ENC];
-        return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
-      }
-      else if (ptr[1] == '\0') {
-        /* We could recover here in the case:
-            - parsing an external entity
-            - second byte is 0
-            - no externally specified encoding
-            - no encoding declaration
-           by assuming UTF-16LE.  But we don't, because this would mean when
-           presented just with a single byte, we couldn't reliably determine
-           whether we needed further bytes.
-        */
-        if (state == XML_CONTENT_STATE)
-          break;
-        *encPtr = encodingTable[UTF_16LE_ENC];
-        return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
-      }
-      break;
-    }
-  }
-  *encPtr = encodingTable[INIT_ENC_INDEX(enc)];
-  return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
-}
-
-
-#define NS(x) x
-#define ns(x) x
-#define XML_TOK_NS_C
-#include "xmltok_ns.c"
-#undef XML_TOK_NS_C
-#undef NS
-#undef ns
-
-#ifdef XML_NS
-
-#define NS(x) x ## NS
-#define ns(x) x ## _ns
-
-#define XML_TOK_NS_C
-#include "xmltok_ns.c"
-#undef XML_TOK_NS_C
-
-#undef NS
-#undef ns
-
-ENCODING *
-XmlInitUnknownEncodingNS(void *mem,
-                         int *table,
-                         CONVERTER convert,
-                         void *userData)
-{
-  ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData);
-  if (enc)
-    ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON;
-  return enc;
-}
-
-#endif /* XML_NS */
diff --git a/components/expat/library/xmltok_impl.c b/components/expat/library/xmltok_impl.c
deleted file mode 100644 (file)
index b785129..0000000
+++ /dev/null
@@ -1,1782 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-/* This file is included! */
-#ifdef XML_TOK_IMPL_C
-
-#ifndef IS_INVALID_CHAR
-#define IS_INVALID_CHAR(enc, ptr, n) (0)
-#endif
-
-#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \
-    case BT_LEAD ## n: \
-      if (end - ptr < n) \
-        return XML_TOK_PARTIAL_CHAR; \
-      if (IS_INVALID_CHAR(enc, ptr, n)) { \
-        *(nextTokPtr) = (ptr); \
-        return XML_TOK_INVALID; \
-      } \
-      ptr += n; \
-      break;
-
-#define INVALID_CASES(ptr, nextTokPtr) \
-  INVALID_LEAD_CASE(2, ptr, nextTokPtr) \
-  INVALID_LEAD_CASE(3, ptr, nextTokPtr) \
-  INVALID_LEAD_CASE(4, ptr, nextTokPtr) \
-  case BT_NONXML: \
-  case BT_MALFORM: \
-  case BT_TRAIL: \
-    *(nextTokPtr) = (ptr); \
-    return XML_TOK_INVALID;
-
-#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \
-   case BT_LEAD ## n: \
-     if (end - ptr < n) \
-       return XML_TOK_PARTIAL_CHAR; \
-     if (!IS_NAME_CHAR(enc, ptr, n)) { \
-       *nextTokPtr = ptr; \
-       return XML_TOK_INVALID; \
-     } \
-     ptr += n; \
-     break;
-
-#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \
-  case BT_NONASCII: \
-    if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \
-      *nextTokPtr = ptr; \
-      return XML_TOK_INVALID; \
-    } \
-    /* fall through */ \
-  case BT_NMSTRT: \
-  case BT_HEX: \
-  case BT_DIGIT: \
-  case BT_NAME: \
-  case BT_MINUS: \
-    ptr += MINBPC(enc); \
-    break; \
-  CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \
-  CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \
-  CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr)
-
-#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \
-   case BT_LEAD ## n: \
-     if (end - ptr < n) \
-       return XML_TOK_PARTIAL_CHAR; \
-     if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \
-       *nextTokPtr = ptr; \
-       return XML_TOK_INVALID; \
-     } \
-     ptr += n; \
-     break;
-
-#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \
-  case BT_NONASCII: \
-    if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \
-      *nextTokPtr = ptr; \
-      return XML_TOK_INVALID; \
-    } \
-    /* fall through */ \
-  case BT_NMSTRT: \
-  case BT_HEX: \
-    ptr += MINBPC(enc); \
-    break; \
-  CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \
-  CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \
-  CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr)
-
-#ifndef PREFIX
-#define PREFIX(ident) ident
-#endif
-
-
-#define HAS_CHARS(enc, ptr, end, count) \
-    (end - ptr >= count * MINBPC(enc))
-
-#define HAS_CHAR(enc, ptr, end) \
-    HAS_CHARS(enc, ptr, end, 1)
-
-#define REQUIRE_CHARS(enc, ptr, end, count) \
-    { \
-      if (! HAS_CHARS(enc, ptr, end, count)) { \
-        return XML_TOK_PARTIAL; \
-      } \
-    }
-
-#define REQUIRE_CHAR(enc, ptr, end) \
-    REQUIRE_CHARS(enc, ptr, end, 1)
-
-
-/* ptr points to character following "<!-" */
-
-static int PTRCALL
-PREFIX(scanComment)(const ENCODING *enc, const char *ptr,
-                    const char *end, const char **nextTokPtr)
-{
-  if (HAS_CHAR(enc, ptr, end)) {
-    if (!CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-    ptr += MINBPC(enc);
-    while (HAS_CHAR(enc, ptr, end)) {
-      switch (BYTE_TYPE(enc, ptr)) {
-      INVALID_CASES(ptr, nextTokPtr)
-      case BT_MINUS:
-        ptr += MINBPC(enc);
-        REQUIRE_CHAR(enc, ptr, end);
-        if (CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
-          ptr += MINBPC(enc);
-          REQUIRE_CHAR(enc, ptr, end);
-          if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
-            *nextTokPtr = ptr;
-            return XML_TOK_INVALID;
-          }
-          *nextTokPtr = ptr + MINBPC(enc);
-          return XML_TOK_COMMENT;
-        }
-        break;
-      default:
-        ptr += MINBPC(enc);
-        break;
-      }
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following "<!" */
-
-static int PTRCALL
-PREFIX(scanDecl)(const ENCODING *enc, const char *ptr,
-                 const char *end, const char **nextTokPtr)
-{
-  REQUIRE_CHAR(enc, ptr, end);
-  switch (BYTE_TYPE(enc, ptr)) {
-  case BT_MINUS:
-    return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-  case BT_LSQB:
-    *nextTokPtr = ptr + MINBPC(enc);
-    return XML_TOK_COND_SECT_OPEN;
-  case BT_NMSTRT:
-  case BT_HEX:
-    ptr += MINBPC(enc);
-    break;
-  default:
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  }
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    case BT_PERCNT:
-      REQUIRE_CHARS(enc, ptr, end, 2);
-      /* don't allow <!ENTITY% foo "whatever"> */
-      switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) {
-      case BT_S: case BT_CR: case BT_LF: case BT_PERCNT:
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      /* fall through */
-    case BT_S: case BT_CR: case BT_LF:
-      *nextTokPtr = ptr;
-      return XML_TOK_DECL_OPEN;
-    case BT_NMSTRT:
-    case BT_HEX:
-      ptr += MINBPC(enc);
-      break;
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-static int PTRCALL
-PREFIX(checkPiTarget)(const ENCODING *UNUSED_P(enc), const char *ptr,
-                      const char *end, int *tokPtr)
-{
-  int upper = 0;
-  *tokPtr = XML_TOK_PI;
-  if (end - ptr != MINBPC(enc)*3)
-    return 1;
-  switch (BYTE_TO_ASCII(enc, ptr)) {
-  case ASCII_x:
-    break;
-  case ASCII_X:
-    upper = 1;
-    break;
-  default:
-    return 1;
-  }
-  ptr += MINBPC(enc);
-  switch (BYTE_TO_ASCII(enc, ptr)) {
-  case ASCII_m:
-    break;
-  case ASCII_M:
-    upper = 1;
-    break;
-  default:
-    return 1;
-  }
-  ptr += MINBPC(enc);
-  switch (BYTE_TO_ASCII(enc, ptr)) {
-  case ASCII_l:
-    break;
-  case ASCII_L:
-    upper = 1;
-    break;
-  default:
-    return 1;
-  }
-  if (upper)
-    return 0;
-  *tokPtr = XML_TOK_XML_DECL;
-  return 1;
-}
-
-/* ptr points to character following "<?" */
-
-static int PTRCALL
-PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
-               const char *end, const char **nextTokPtr)
-{
-  int tok;
-  const char *target = ptr;
-  REQUIRE_CHAR(enc, ptr, end);
-  switch (BYTE_TYPE(enc, ptr)) {
-  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
-  default:
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  }
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-    case BT_S: case BT_CR: case BT_LF:
-      if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      ptr += MINBPC(enc);
-      while (HAS_CHAR(enc, ptr, end)) {
-        switch (BYTE_TYPE(enc, ptr)) {
-        INVALID_CASES(ptr, nextTokPtr)
-        case BT_QUEST:
-          ptr += MINBPC(enc);
-          REQUIRE_CHAR(enc, ptr, end);
-          if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
-            *nextTokPtr = ptr + MINBPC(enc);
-            return tok;
-          }
-          break;
-        default:
-          ptr += MINBPC(enc);
-          break;
-        }
-      }
-      return XML_TOK_PARTIAL;
-    case BT_QUEST:
-      if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      ptr += MINBPC(enc);
-      REQUIRE_CHAR(enc, ptr, end);
-      if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
-        *nextTokPtr = ptr + MINBPC(enc);
-        return tok;
-      }
-      /* fall through */
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-static int PTRCALL
-PREFIX(scanCdataSection)(const ENCODING *UNUSED_P(enc), const char *ptr,
-                         const char *end, const char **nextTokPtr)
-{
-  static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A,
-                                     ASCII_T, ASCII_A, ASCII_LSQB };
-  int i;
-  /* CDATA[ */
-  REQUIRE_CHARS(enc, ptr, end, 6);
-  for (i = 0; i < 6; i++, ptr += MINBPC(enc)) {
-    if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) {
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  }
-  *nextTokPtr = ptr;
-  return XML_TOK_CDATA_SECT_OPEN;
-}
-
-static int PTRCALL
-PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
-                        const char *end, const char **nextTokPtr)
-{
-  if (ptr >= end)
-    return XML_TOK_NONE;
-  if (MINBPC(enc) > 1) {
-    size_t n = end - ptr;
-    if (n & (MINBPC(enc) - 1)) {
-      n &= ~(MINBPC(enc) - 1);
-      if (n == 0)
-        return XML_TOK_PARTIAL;
-      end = ptr + n;
-    }
-  }
-  switch (BYTE_TYPE(enc, ptr)) {
-  case BT_RSQB:
-    ptr += MINBPC(enc);
-    REQUIRE_CHAR(enc, ptr, end);
-    if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
-      break;
-    ptr += MINBPC(enc);
-    REQUIRE_CHAR(enc, ptr, end);
-    if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
-      ptr -= MINBPC(enc);
-      break;
-    }
-    *nextTokPtr = ptr + MINBPC(enc);
-    return XML_TOK_CDATA_SECT_CLOSE;
-  case BT_CR:
-    ptr += MINBPC(enc);
-    REQUIRE_CHAR(enc, ptr, end);
-    if (BYTE_TYPE(enc, ptr) == BT_LF)
-      ptr += MINBPC(enc);
-    *nextTokPtr = ptr;
-    return XML_TOK_DATA_NEWLINE;
-  case BT_LF:
-    *nextTokPtr = ptr + MINBPC(enc);
-    return XML_TOK_DATA_NEWLINE;
-  INVALID_CASES(ptr, nextTokPtr)
-  default:
-    ptr += MINBPC(enc);
-    break;
-  }
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
-    case BT_LEAD ## n: \
-      if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
-        *nextTokPtr = ptr; \
-        return XML_TOK_DATA_CHARS; \
-      } \
-      ptr += n; \
-      break;
-    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
-    case BT_NONXML:
-    case BT_MALFORM:
-    case BT_TRAIL:
-    case BT_CR:
-    case BT_LF:
-    case BT_RSQB:
-      *nextTokPtr = ptr;
-      return XML_TOK_DATA_CHARS;
-    default:
-      ptr += MINBPC(enc);
-      break;
-    }
-  }
-  *nextTokPtr = ptr;
-  return XML_TOK_DATA_CHARS;
-}
-
-/* ptr points to character following "</" */
-
-static int PTRCALL
-PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr,
-                   const char *end, const char **nextTokPtr)
-{
-  REQUIRE_CHAR(enc, ptr, end);
-  switch (BYTE_TYPE(enc, ptr)) {
-  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
-  default:
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  }
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-    case BT_S: case BT_CR: case BT_LF:
-      for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
-        switch (BYTE_TYPE(enc, ptr)) {
-        case BT_S: case BT_CR: case BT_LF:
-          break;
-        case BT_GT:
-          *nextTokPtr = ptr + MINBPC(enc);
-          return XML_TOK_END_TAG;
-        default:
-          *nextTokPtr = ptr;
-          return XML_TOK_INVALID;
-        }
-      }
-      return XML_TOK_PARTIAL;
-#ifdef XML_NS
-    case BT_COLON:
-      /* no need to check qname syntax here,
-         since end-tag must match exactly */
-      ptr += MINBPC(enc);
-      break;
-#endif
-    case BT_GT:
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_END_TAG;
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following "&#X" */
-
-static int PTRCALL
-PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
-                       const char *end, const char **nextTokPtr)
-{
-  if (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    case BT_DIGIT:
-    case BT_HEX:
-      break;
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-    for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
-      switch (BYTE_TYPE(enc, ptr)) {
-      case BT_DIGIT:
-      case BT_HEX:
-        break;
-      case BT_SEMI:
-        *nextTokPtr = ptr + MINBPC(enc);
-        return XML_TOK_CHAR_REF;
-      default:
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following "&#" */
-
-static int PTRCALL
-PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
-                    const char *end, const char **nextTokPtr)
-{
-  if (HAS_CHAR(enc, ptr, end)) {
-    if (CHAR_MATCHES(enc, ptr, ASCII_x))
-      return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-    switch (BYTE_TYPE(enc, ptr)) {
-    case BT_DIGIT:
-      break;
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-    for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
-      switch (BYTE_TYPE(enc, ptr)) {
-      case BT_DIGIT:
-        break;
-      case BT_SEMI:
-        *nextTokPtr = ptr + MINBPC(enc);
-        return XML_TOK_CHAR_REF;
-      default:
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following "&" */
-
-static int PTRCALL
-PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
-                const char **nextTokPtr)
-{
-  REQUIRE_CHAR(enc, ptr, end);
-  switch (BYTE_TYPE(enc, ptr)) {
-  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
-  case BT_NUM:
-    return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-  default:
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  }
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-    case BT_SEMI:
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_ENTITY_REF;
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following first character of attribute name */
-
-static int PTRCALL
-PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
-                 const char **nextTokPtr)
-{
-#ifdef XML_NS
-  int hadColon = 0;
-#endif
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-#ifdef XML_NS
-    case BT_COLON:
-      if (hadColon) {
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      hadColon = 1;
-      ptr += MINBPC(enc);
-      REQUIRE_CHAR(enc, ptr, end);
-      switch (BYTE_TYPE(enc, ptr)) {
-      CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
-      default:
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      break;
-#endif
-    case BT_S: case BT_CR: case BT_LF:
-      for (;;) {
-        int t;
-
-        ptr += MINBPC(enc);
-        REQUIRE_CHAR(enc, ptr, end);
-        t = BYTE_TYPE(enc, ptr);
-        if (t == BT_EQUALS)
-          break;
-        switch (t) {
-        case BT_S:
-        case BT_LF:
-        case BT_CR:
-          break;
-        default:
-          *nextTokPtr = ptr;
-          return XML_TOK_INVALID;
-        }
-      }
-      /* fall through */
-    case BT_EQUALS:
-      {
-        int open;
-#ifdef XML_NS
-        hadColon = 0;
-#endif
-        for (;;) {
-          ptr += MINBPC(enc);
-          REQUIRE_CHAR(enc, ptr, end);
-          open = BYTE_TYPE(enc, ptr);
-          if (open == BT_QUOT || open == BT_APOS)
-            break;
-          switch (open) {
-          case BT_S:
-          case BT_LF:
-          case BT_CR:
-            break;
-          default:
-            *nextTokPtr = ptr;
-            return XML_TOK_INVALID;
-          }
-        }
-        ptr += MINBPC(enc);
-        /* in attribute value */
-        for (;;) {
-          int t;
-          REQUIRE_CHAR(enc, ptr, end);
-          t = BYTE_TYPE(enc, ptr);
-          if (t == open)
-            break;
-          switch (t) {
-          INVALID_CASES(ptr, nextTokPtr)
-          case BT_AMP:
-            {
-              int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr);
-              if (tok <= 0) {
-                if (tok == XML_TOK_INVALID)
-                  *nextTokPtr = ptr;
-                return tok;
-              }
-              break;
-            }
-          case BT_LT:
-            *nextTokPtr = ptr;
-            return XML_TOK_INVALID;
-          default:
-            ptr += MINBPC(enc);
-            break;
-          }
-        }
-        ptr += MINBPC(enc);
-        REQUIRE_CHAR(enc, ptr, end);
-        switch (BYTE_TYPE(enc, ptr)) {
-        case BT_S:
-        case BT_CR:
-        case BT_LF:
-          break;
-        case BT_SOL:
-          goto sol;
-        case BT_GT:
-          goto gt;
-        default:
-          *nextTokPtr = ptr;
-          return XML_TOK_INVALID;
-        }
-        /* ptr points to closing quote */
-        for (;;) {
-          ptr += MINBPC(enc);
-          REQUIRE_CHAR(enc, ptr, end);
-          switch (BYTE_TYPE(enc, ptr)) {
-          CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
-          case BT_S: case BT_CR: case BT_LF:
-            continue;
-          case BT_GT:
-          gt:
-            *nextTokPtr = ptr + MINBPC(enc);
-            return XML_TOK_START_TAG_WITH_ATTS;
-          case BT_SOL:
-          sol:
-            ptr += MINBPC(enc);
-            REQUIRE_CHAR(enc, ptr, end);
-            if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
-              *nextTokPtr = ptr;
-              return XML_TOK_INVALID;
-            }
-            *nextTokPtr = ptr + MINBPC(enc);
-            return XML_TOK_EMPTY_ELEMENT_WITH_ATTS;
-          default:
-            *nextTokPtr = ptr;
-            return XML_TOK_INVALID;
-          }
-          break;
-        }
-        break;
-      }
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following "<" */
-
-static int PTRCALL
-PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
-               const char **nextTokPtr)
-{
-#ifdef XML_NS
-  int hadColon;
-#endif
-  REQUIRE_CHAR(enc, ptr, end);
-  switch (BYTE_TYPE(enc, ptr)) {
-  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
-  case BT_EXCL:
-    ptr += MINBPC(enc);
-    REQUIRE_CHAR(enc, ptr, end);
-    switch (BYTE_TYPE(enc, ptr)) {
-    case BT_MINUS:
-      return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-    case BT_LSQB:
-      return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc),
-                                      end, nextTokPtr);
-    }
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  case BT_QUEST:
-    return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-  case BT_SOL:
-    return PREFIX(scanEndTag)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-  default:
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  }
-#ifdef XML_NS
-  hadColon = 0;
-#endif
-  /* we have a start-tag */
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-#ifdef XML_NS
-    case BT_COLON:
-      if (hadColon) {
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      hadColon = 1;
-      ptr += MINBPC(enc);
-      REQUIRE_CHAR(enc, ptr, end);
-      switch (BYTE_TYPE(enc, ptr)) {
-      CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
-      default:
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      break;
-#endif
-    case BT_S: case BT_CR: case BT_LF:
-      {
-        ptr += MINBPC(enc);
-        while (HAS_CHAR(enc, ptr, end)) {
-          switch (BYTE_TYPE(enc, ptr)) {
-          CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
-          case BT_GT:
-            goto gt;
-          case BT_SOL:
-            goto sol;
-          case BT_S: case BT_CR: case BT_LF:
-            ptr += MINBPC(enc);
-            continue;
-          default:
-            *nextTokPtr = ptr;
-            return XML_TOK_INVALID;
-          }
-          return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr);
-        }
-        return XML_TOK_PARTIAL;
-      }
-    case BT_GT:
-    gt:
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_START_TAG_NO_ATTS;
-    case BT_SOL:
-    sol:
-      ptr += MINBPC(enc);
-      REQUIRE_CHAR(enc, ptr, end);
-      if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_EMPTY_ELEMENT_NO_ATTS;
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-static int PTRCALL
-PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
-                   const char **nextTokPtr)
-{
-  if (ptr >= end)
-    return XML_TOK_NONE;
-  if (MINBPC(enc) > 1) {
-    size_t n = end - ptr;
-    if (n & (MINBPC(enc) - 1)) {
-      n &= ~(MINBPC(enc) - 1);
-      if (n == 0)
-        return XML_TOK_PARTIAL;
-      end = ptr + n;
-    }
-  }
-  switch (BYTE_TYPE(enc, ptr)) {
-  case BT_LT:
-    return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-  case BT_AMP:
-    return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-  case BT_CR:
-    ptr += MINBPC(enc);
-    if (! HAS_CHAR(enc, ptr, end))
-      return XML_TOK_TRAILING_CR;
-    if (BYTE_TYPE(enc, ptr) == BT_LF)
-      ptr += MINBPC(enc);
-    *nextTokPtr = ptr;
-    return XML_TOK_DATA_NEWLINE;
-  case BT_LF:
-    *nextTokPtr = ptr + MINBPC(enc);
-    return XML_TOK_DATA_NEWLINE;
-  case BT_RSQB:
-    ptr += MINBPC(enc);
-    if (! HAS_CHAR(enc, ptr, end))
-      return XML_TOK_TRAILING_RSQB;
-    if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
-      break;
-    ptr += MINBPC(enc);
-    if (! HAS_CHAR(enc, ptr, end))
-      return XML_TOK_TRAILING_RSQB;
-    if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
-      ptr -= MINBPC(enc);
-      break;
-    }
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  INVALID_CASES(ptr, nextTokPtr)
-  default:
-    ptr += MINBPC(enc);
-    break;
-  }
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
-    case BT_LEAD ## n: \
-      if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
-        *nextTokPtr = ptr; \
-        return XML_TOK_DATA_CHARS; \
-      } \
-      ptr += n; \
-      break;
-    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
-    case BT_RSQB:
-      if (HAS_CHARS(enc, ptr, end, 2)) {
-         if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) {
-           ptr += MINBPC(enc);
-           break;
-         }
-         if (HAS_CHARS(enc, ptr, end, 3)) {
-           if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) {
-             ptr += MINBPC(enc);
-             break;
-           }
-           *nextTokPtr = ptr + 2*MINBPC(enc);
-           return XML_TOK_INVALID;
-         }
-      }
-      /* fall through */
-    case BT_AMP:
-    case BT_LT:
-    case BT_NONXML:
-    case BT_MALFORM:
-    case BT_TRAIL:
-    case BT_CR:
-    case BT_LF:
-      *nextTokPtr = ptr;
-      return XML_TOK_DATA_CHARS;
-    default:
-      ptr += MINBPC(enc);
-      break;
-    }
-  }
-  *nextTokPtr = ptr;
-  return XML_TOK_DATA_CHARS;
-}
-
-/* ptr points to character following "%" */
-
-static int PTRCALL
-PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
-                    const char **nextTokPtr)
-{
-  REQUIRE_CHAR(enc, ptr, end);
-  switch (BYTE_TYPE(enc, ptr)) {
-  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
-  case BT_S: case BT_LF: case BT_CR: case BT_PERCNT:
-    *nextTokPtr = ptr;
-    return XML_TOK_PERCENT;
-  default:
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  }
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-    case BT_SEMI:
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_PARAM_ENTITY_REF;
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-static int PTRCALL
-PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
-                      const char **nextTokPtr)
-{
-  REQUIRE_CHAR(enc, ptr, end);
-  switch (BYTE_TYPE(enc, ptr)) {
-  CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
-  default:
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  }
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-    case BT_CR: case BT_LF: case BT_S:
-    case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR:
-      *nextTokPtr = ptr;
-      return XML_TOK_POUND_NAME;
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  }
-  return -XML_TOK_POUND_NAME;
-}
-
-static int PTRCALL
-PREFIX(scanLit)(int open, const ENCODING *enc,
-                const char *ptr, const char *end,
-                const char **nextTokPtr)
-{
-  while (HAS_CHAR(enc, ptr, end)) {
-    int t = BYTE_TYPE(enc, ptr);
-    switch (t) {
-    INVALID_CASES(ptr, nextTokPtr)
-    case BT_QUOT:
-    case BT_APOS:
-      ptr += MINBPC(enc);
-      if (t != open)
-        break;
-      if (! HAS_CHAR(enc, ptr, end))
-        return -XML_TOK_LITERAL;
-      *nextTokPtr = ptr;
-      switch (BYTE_TYPE(enc, ptr)) {
-      case BT_S: case BT_CR: case BT_LF:
-      case BT_GT: case BT_PERCNT: case BT_LSQB:
-        return XML_TOK_LITERAL;
-      default:
-        return XML_TOK_INVALID;
-      }
-    default:
-      ptr += MINBPC(enc);
-      break;
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-static int PTRCALL
-PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
-                  const char **nextTokPtr)
-{
-  int tok;
-  if (ptr >= end)
-    return XML_TOK_NONE;
-  if (MINBPC(enc) > 1) {
-    size_t n = end - ptr;
-    if (n & (MINBPC(enc) - 1)) {
-      n &= ~(MINBPC(enc) - 1);
-      if (n == 0)
-        return XML_TOK_PARTIAL;
-      end = ptr + n;
-    }
-  }
-  switch (BYTE_TYPE(enc, ptr)) {
-  case BT_QUOT:
-    return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr);
-  case BT_APOS:
-    return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr);
-  case BT_LT:
-    {
-      ptr += MINBPC(enc);
-      REQUIRE_CHAR(enc, ptr, end);
-      switch (BYTE_TYPE(enc, ptr)) {
-      case BT_EXCL:
-        return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-      case BT_QUEST:
-        return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-      case BT_NMSTRT:
-      case BT_HEX:
-      case BT_NONASCII:
-      case BT_LEAD2:
-      case BT_LEAD3:
-      case BT_LEAD4:
-        *nextTokPtr = ptr - MINBPC(enc);
-        return XML_TOK_INSTANCE_START;
-      }
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  case BT_CR:
-    if (ptr + MINBPC(enc) == end) {
-      *nextTokPtr = end;
-      /* indicate that this might be part of a CR/LF pair */
-      return -XML_TOK_PROLOG_S;
-    }
-    /* fall through */
-  case BT_S: case BT_LF:
-    for (;;) {
-      ptr += MINBPC(enc);
-      if (! HAS_CHAR(enc, ptr, end))
-        break;
-      switch (BYTE_TYPE(enc, ptr)) {
-      case BT_S: case BT_LF:
-        break;
-      case BT_CR:
-        /* don't split CR/LF pair */
-        if (ptr + MINBPC(enc) != end)
-          break;
-        /* fall through */
-      default:
-        *nextTokPtr = ptr;
-        return XML_TOK_PROLOG_S;
-      }
-    }
-    *nextTokPtr = ptr;
-    return XML_TOK_PROLOG_S;
-  case BT_PERCNT:
-    return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-  case BT_COMMA:
-    *nextTokPtr = ptr + MINBPC(enc);
-    return XML_TOK_COMMA;
-  case BT_LSQB:
-    *nextTokPtr = ptr + MINBPC(enc);
-    return XML_TOK_OPEN_BRACKET;
-  case BT_RSQB:
-    ptr += MINBPC(enc);
-    if (! HAS_CHAR(enc, ptr, end))
-      return -XML_TOK_CLOSE_BRACKET;
-    if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
-      REQUIRE_CHARS(enc, ptr, end, 2);
-      if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) {
-        *nextTokPtr = ptr + 2*MINBPC(enc);
-        return XML_TOK_COND_SECT_CLOSE;
-      }
-    }
-    *nextTokPtr = ptr;
-    return XML_TOK_CLOSE_BRACKET;
-  case BT_LPAR:
-    *nextTokPtr = ptr + MINBPC(enc);
-    return XML_TOK_OPEN_PAREN;
-  case BT_RPAR:
-    ptr += MINBPC(enc);
-    if (! HAS_CHAR(enc, ptr, end))
-      return -XML_TOK_CLOSE_PAREN;
-    switch (BYTE_TYPE(enc, ptr)) {
-    case BT_AST:
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_CLOSE_PAREN_ASTERISK;
-    case BT_QUEST:
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_CLOSE_PAREN_QUESTION;
-    case BT_PLUS:
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_CLOSE_PAREN_PLUS;
-    case BT_CR: case BT_LF: case BT_S:
-    case BT_GT: case BT_COMMA: case BT_VERBAR:
-    case BT_RPAR:
-      *nextTokPtr = ptr;
-      return XML_TOK_CLOSE_PAREN;
-    }
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  case BT_VERBAR:
-    *nextTokPtr = ptr + MINBPC(enc);
-    return XML_TOK_OR;
-  case BT_GT:
-    *nextTokPtr = ptr + MINBPC(enc);
-    return XML_TOK_DECL_CLOSE;
-  case BT_NUM:
-    return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-#define LEAD_CASE(n) \
-  case BT_LEAD ## n: \
-    if (end - ptr < n) \
-      return XML_TOK_PARTIAL_CHAR; \
-    if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
-      ptr += n; \
-      tok = XML_TOK_NAME; \
-      break; \
-    } \
-    if (IS_NAME_CHAR(enc, ptr, n)) { \
-      ptr += n; \
-      tok = XML_TOK_NMTOKEN; \
-      break; \
-    } \
-    *nextTokPtr = ptr; \
-    return XML_TOK_INVALID;
-    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
-  case BT_NMSTRT:
-  case BT_HEX:
-    tok = XML_TOK_NAME;
-    ptr += MINBPC(enc);
-    break;
-  case BT_DIGIT:
-  case BT_NAME:
-  case BT_MINUS:
-#ifdef XML_NS
-  case BT_COLON:
-#endif
-    tok = XML_TOK_NMTOKEN;
-    ptr += MINBPC(enc);
-    break;
-  case BT_NONASCII:
-    if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) {
-      ptr += MINBPC(enc);
-      tok = XML_TOK_NAME;
-      break;
-    }
-    if (IS_NAME_CHAR_MINBPC(enc, ptr)) {
-      ptr += MINBPC(enc);
-      tok = XML_TOK_NMTOKEN;
-      break;
-    }
-    /* fall through */
-  default:
-    *nextTokPtr = ptr;
-    return XML_TOK_INVALID;
-  }
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-    case BT_GT: case BT_RPAR: case BT_COMMA:
-    case BT_VERBAR: case BT_LSQB: case BT_PERCNT:
-    case BT_S: case BT_CR: case BT_LF:
-      *nextTokPtr = ptr;
-      return tok;
-#ifdef XML_NS
-    case BT_COLON:
-      ptr += MINBPC(enc);
-      switch (tok) {
-      case XML_TOK_NAME:
-        REQUIRE_CHAR(enc, ptr, end);
-        tok = XML_TOK_PREFIXED_NAME;
-        switch (BYTE_TYPE(enc, ptr)) {
-        CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-        default:
-          tok = XML_TOK_NMTOKEN;
-          break;
-        }
-        break;
-      case XML_TOK_PREFIXED_NAME:
-        tok = XML_TOK_NMTOKEN;
-        break;
-      }
-      break;
-#endif
-    case BT_PLUS:
-      if (tok == XML_TOK_NMTOKEN)  {
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_NAME_PLUS;
-    case BT_AST:
-      if (tok == XML_TOK_NMTOKEN)  {
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_NAME_ASTERISK;
-    case BT_QUEST:
-      if (tok == XML_TOK_NMTOKEN)  {
-        *nextTokPtr = ptr;
-        return XML_TOK_INVALID;
-      }
-      *nextTokPtr = ptr + MINBPC(enc);
-      return XML_TOK_NAME_QUESTION;
-    default:
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    }
-  }
-  return -tok;
-}
-
-static int PTRCALL
-PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr,
-                          const char *end, const char **nextTokPtr)
-{
-  const char *start;
-  if (ptr >= end)
-    return XML_TOK_NONE;
-  else if (! HAS_CHAR(enc, ptr, end))
-    return XML_TOK_PARTIAL;
-  start = ptr;
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
-    case BT_LEAD ## n: ptr += n; break;
-    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
-    case BT_AMP:
-      if (ptr == start)
-        return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-      *nextTokPtr = ptr;
-      return XML_TOK_DATA_CHARS;
-    case BT_LT:
-      /* this is for inside entity references */
-      *nextTokPtr = ptr;
-      return XML_TOK_INVALID;
-    case BT_LF:
-      if (ptr == start) {
-        *nextTokPtr = ptr + MINBPC(enc);
-        return XML_TOK_DATA_NEWLINE;
-      }
-      *nextTokPtr = ptr;
-      return XML_TOK_DATA_CHARS;
-    case BT_CR:
-      if (ptr == start) {
-        ptr += MINBPC(enc);
-        if (! HAS_CHAR(enc, ptr, end))
-          return XML_TOK_TRAILING_CR;
-        if (BYTE_TYPE(enc, ptr) == BT_LF)
-          ptr += MINBPC(enc);
-        *nextTokPtr = ptr;
-        return XML_TOK_DATA_NEWLINE;
-      }
-      *nextTokPtr = ptr;
-      return XML_TOK_DATA_CHARS;
-    case BT_S:
-      if (ptr == start) {
-        *nextTokPtr = ptr + MINBPC(enc);
-        return XML_TOK_ATTRIBUTE_VALUE_S;
-      }
-      *nextTokPtr = ptr;
-      return XML_TOK_DATA_CHARS;
-    default:
-      ptr += MINBPC(enc);
-      break;
-    }
-  }
-  *nextTokPtr = ptr;
-  return XML_TOK_DATA_CHARS;
-}
-
-static int PTRCALL
-PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
-                       const char *end, const char **nextTokPtr)
-{
-  const char *start;
-  if (ptr >= end)
-    return XML_TOK_NONE;
-  else if (! HAS_CHAR(enc, ptr, end))
-    return XML_TOK_PARTIAL;
-  start = ptr;
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
-    case BT_LEAD ## n: ptr += n; break;
-    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
-    case BT_AMP:
-      if (ptr == start)
-        return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-      *nextTokPtr = ptr;
-      return XML_TOK_DATA_CHARS;
-    case BT_PERCNT:
-      if (ptr == start) {
-        int tok =  PREFIX(scanPercent)(enc, ptr + MINBPC(enc),
-                                       end, nextTokPtr);
-        return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok;
-      }
-      *nextTokPtr = ptr;
-      return XML_TOK_DATA_CHARS;
-    case BT_LF:
-      if (ptr == start) {
-        *nextTokPtr = ptr + MINBPC(enc);
-        return XML_TOK_DATA_NEWLINE;
-      }
-      *nextTokPtr = ptr;
-      return XML_TOK_DATA_CHARS;
-    case BT_CR:
-      if (ptr == start) {
-        ptr += MINBPC(enc);
-        if (! HAS_CHAR(enc, ptr, end))
-          return XML_TOK_TRAILING_CR;
-        if (BYTE_TYPE(enc, ptr) == BT_LF)
-          ptr += MINBPC(enc);
-        *nextTokPtr = ptr;
-        return XML_TOK_DATA_NEWLINE;
-      }
-      *nextTokPtr = ptr;
-      return XML_TOK_DATA_CHARS;
-    default:
-      ptr += MINBPC(enc);
-      break;
-    }
-  }
-  *nextTokPtr = ptr;
-  return XML_TOK_DATA_CHARS;
-}
-
-#ifdef XML_DTD
-
-static int PTRCALL
-PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
-                         const char *end, const char **nextTokPtr)
-{
-  int level = 0;
-  if (MINBPC(enc) > 1) {
-    size_t n = end - ptr;
-    if (n & (MINBPC(enc) - 1)) {
-      n &= ~(MINBPC(enc) - 1);
-      end = ptr + n;
-    }
-  }
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    INVALID_CASES(ptr, nextTokPtr)
-    case BT_LT:
-      ptr += MINBPC(enc);
-      REQUIRE_CHAR(enc, ptr, end);
-      if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) {
-        ptr += MINBPC(enc);
-        REQUIRE_CHAR(enc, ptr, end);
-        if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) {
-          ++level;
-          ptr += MINBPC(enc);
-        }
-      }
-      break;
-    case BT_RSQB:
-      ptr += MINBPC(enc);
-      REQUIRE_CHAR(enc, ptr, end);
-      if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
-        ptr += MINBPC(enc);
-        REQUIRE_CHAR(enc, ptr, end);
-        if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
-          ptr += MINBPC(enc);
-          if (level == 0) {
-            *nextTokPtr = ptr;
-            return XML_TOK_IGNORE_SECT;
-          }
-          --level;
-        }
-      }
-      break;
-    default:
-      ptr += MINBPC(enc);
-      break;
-    }
-  }
-  return XML_TOK_PARTIAL;
-}
-
-#endif /* XML_DTD */
-
-static int PTRCALL
-PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
-                   const char **badPtr)
-{
-  ptr += MINBPC(enc);
-  end -= MINBPC(enc);
-  for (; HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    case BT_DIGIT:
-    case BT_HEX:
-    case BT_MINUS:
-    case BT_APOS:
-    case BT_LPAR:
-    case BT_RPAR:
-    case BT_PLUS:
-    case BT_COMMA:
-    case BT_SOL:
-    case BT_EQUALS:
-    case BT_QUEST:
-    case BT_CR:
-    case BT_LF:
-    case BT_SEMI:
-    case BT_EXCL:
-    case BT_AST:
-    case BT_PERCNT:
-    case BT_NUM:
-#ifdef XML_NS
-    case BT_COLON:
-#endif
-      break;
-    case BT_S:
-      if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) {
-        *badPtr = ptr;
-        return 0;
-      }
-      break;
-    case BT_NAME:
-    case BT_NMSTRT:
-      if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
-        break;
-      /* fall through */
-    default:
-      switch (BYTE_TO_ASCII(enc, ptr)) {
-      case 0x24: /* $ */
-      case 0x40: /* @ */
-        break;
-      default:
-        *badPtr = ptr;
-        return 0;
-      }
-      break;
-    }
-  }
-  return 1;
-}
-
-/* This must only be called for a well-formed start-tag or empty
-   element tag.  Returns the number of attributes.  Pointers to the
-   first attsMax attributes are stored in atts.
-*/
-
-static int PTRCALL
-PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
-                int attsMax, ATTRIBUTE *atts)
-{
-  enum { other, inName, inValue } state = inName;
-  int nAtts = 0;
-  int open = 0; /* defined when state == inValue;
-                   initialization just to shut up compilers */
-
-  for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-#define START_NAME \
-      if (state == other) { \
-        if (nAtts < attsMax) { \
-          atts[nAtts].name = ptr; \
-          atts[nAtts].normalized = 1; \
-        } \
-        state = inName; \
-      }
-#define LEAD_CASE(n) \
-    case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break;
-    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
-    case BT_NONASCII:
-    case BT_NMSTRT:
-    case BT_HEX:
-      START_NAME
-      break;
-#undef START_NAME
-    case BT_QUOT:
-      if (state != inValue) {
-        if (nAtts < attsMax)
-          atts[nAtts].valuePtr = ptr + MINBPC(enc);
-        state = inValue;
-        open = BT_QUOT;
-      }
-      else if (open == BT_QUOT) {
-        state = other;
-        if (nAtts < attsMax)
-          atts[nAtts].valueEnd = ptr;
-        nAtts++;
-      }
-      break;
-    case BT_APOS:
-      if (state != inValue) {
-        if (nAtts < attsMax)
-          atts[nAtts].valuePtr = ptr + MINBPC(enc);
-        state = inValue;
-        open = BT_APOS;
-      }
-      else if (open == BT_APOS) {
-        state = other;
-        if (nAtts < attsMax)
-          atts[nAtts].valueEnd = ptr;
-        nAtts++;
-      }
-      break;
-    case BT_AMP:
-      if (nAtts < attsMax)
-        atts[nAtts].normalized = 0;
-      break;
-    case BT_S:
-      if (state == inName)
-        state = other;
-      else if (state == inValue
-               && nAtts < attsMax
-               && atts[nAtts].normalized
-               && (ptr == atts[nAtts].valuePtr
-                   || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE
-                   || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE
-                   || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open))
-        atts[nAtts].normalized = 0;
-      break;
-    case BT_CR: case BT_LF:
-      /* This case ensures that the first attribute name is counted
-         Apart from that we could just change state on the quote. */
-      if (state == inName)
-        state = other;
-      else if (state == inValue && nAtts < attsMax)
-        atts[nAtts].normalized = 0;
-      break;
-    case BT_GT:
-    case BT_SOL:
-      if (state != inValue)
-        return nAtts;
-      break;
-    default:
-      break;
-    }
-  }
-  /* not reached */
-}
-
-static int PTRFASTCALL
-PREFIX(charRefNumber)(const ENCODING *UNUSED_P(enc), const char *ptr)
-{
-  int result = 0;
-  /* skip &# */
-  ptr += 2*MINBPC(enc);
-  if (CHAR_MATCHES(enc, ptr, ASCII_x)) {
-    for (ptr += MINBPC(enc);
-         !CHAR_MATCHES(enc, ptr, ASCII_SEMI);
-         ptr += MINBPC(enc)) {
-      int c = BYTE_TO_ASCII(enc, ptr);
-      switch (c) {
-      case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4:
-      case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9:
-        result <<= 4;
-        result |= (c - ASCII_0);
-        break;
-      case ASCII_A: case ASCII_B: case ASCII_C:
-      case ASCII_D: case ASCII_E: case ASCII_F:
-        result <<= 4;
-        result += 10 + (c - ASCII_A);
-        break;
-      case ASCII_a: case ASCII_b: case ASCII_c:
-      case ASCII_d: case ASCII_e: case ASCII_f:
-        result <<= 4;
-        result += 10 + (c - ASCII_a);
-        break;
-      }
-      if (result >= 0x110000)
-        return -1;
-    }
-  }
-  else {
-    for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) {
-      int c = BYTE_TO_ASCII(enc, ptr);
-      result *= 10;
-      result += (c - ASCII_0);
-      if (result >= 0x110000)
-        return -1;
-    }
-  }
-  return checkCharRefNumber(result);
-}
-
-static int PTRCALL
-PREFIX(predefinedEntityName)(const ENCODING *UNUSED_P(enc), const char *ptr,
-                             const char *end)
-{
-  switch ((end - ptr)/MINBPC(enc)) {
-  case 2:
-    if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) {
-      switch (BYTE_TO_ASCII(enc, ptr)) {
-      case ASCII_l:
-        return ASCII_LT;
-      case ASCII_g:
-        return ASCII_GT;
-      }
-    }
-    break;
-  case 3:
-    if (CHAR_MATCHES(enc, ptr, ASCII_a)) {
-      ptr += MINBPC(enc);
-      if (CHAR_MATCHES(enc, ptr, ASCII_m)) {
-        ptr += MINBPC(enc);
-        if (CHAR_MATCHES(enc, ptr, ASCII_p))
-          return ASCII_AMP;
-      }
-    }
-    break;
-  case 4:
-    switch (BYTE_TO_ASCII(enc, ptr)) {
-    case ASCII_q:
-      ptr += MINBPC(enc);
-      if (CHAR_MATCHES(enc, ptr, ASCII_u)) {
-        ptr += MINBPC(enc);
-        if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
-          ptr += MINBPC(enc);
-          if (CHAR_MATCHES(enc, ptr, ASCII_t))
-            return ASCII_QUOT;
-        }
-      }
-      break;
-    case ASCII_a:
-      ptr += MINBPC(enc);
-      if (CHAR_MATCHES(enc, ptr, ASCII_p)) {
-        ptr += MINBPC(enc);
-        if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
-          ptr += MINBPC(enc);
-          if (CHAR_MATCHES(enc, ptr, ASCII_s))
-            return ASCII_APOS;
-        }
-      }
-      break;
-    }
-  }
-  return 0;
-}
-
-static int PTRCALL
-PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
-{
-  for (;;) {
-    switch (BYTE_TYPE(enc, ptr1)) {
-#define LEAD_CASE(n) \
-    case BT_LEAD ## n: \
-      if (*ptr1++ != *ptr2++) \
-        return 0;
-    LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2)
-#undef LEAD_CASE
-      /* fall through */
-      if (*ptr1++ != *ptr2++)
-        return 0;
-      break;
-    case BT_NONASCII:
-    case BT_NMSTRT:
-#ifdef XML_NS
-    case BT_COLON:
-#endif
-    case BT_HEX:
-    case BT_DIGIT:
-    case BT_NAME:
-    case BT_MINUS:
-      if (*ptr2++ != *ptr1++)
-        return 0;
-      if (MINBPC(enc) > 1) {
-        if (*ptr2++ != *ptr1++)
-          return 0;
-        if (MINBPC(enc) > 2) {
-          if (*ptr2++ != *ptr1++)
-            return 0;
-          if (MINBPC(enc) > 3) {
-            if (*ptr2++ != *ptr1++)
-              return 0;
-          }
-        }
-      }
-      break;
-    default:
-      if (MINBPC(enc) == 1 && *ptr1 == *ptr2)
-        return 1;
-      switch (BYTE_TYPE(enc, ptr2)) {
-      case BT_LEAD2:
-      case BT_LEAD3:
-      case BT_LEAD4:
-      case BT_NONASCII:
-      case BT_NMSTRT:
-#ifdef XML_NS
-      case BT_COLON:
-#endif
-      case BT_HEX:
-      case BT_DIGIT:
-      case BT_NAME:
-      case BT_MINUS:
-        return 0;
-      default:
-        return 1;
-      }
-    }
-  }
-  /* not reached */
-}
-
-static int PTRCALL
-PREFIX(nameMatchesAscii)(const ENCODING *UNUSED_P(enc), const char *ptr1,
-                         const char *end1, const char *ptr2)
-{
-  for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
-    if (end1 - ptr1 < MINBPC(enc))
-      return 0;
-    if (!CHAR_MATCHES(enc, ptr1, *ptr2))
-      return 0;
-  }
-  return ptr1 == end1;
-}
-
-static int PTRFASTCALL
-PREFIX(nameLength)(const ENCODING *enc, const char *ptr)
-{
-  const char *start = ptr;
-  for (;;) {
-    switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
-    case BT_LEAD ## n: ptr += n; break;
-    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
-    case BT_NONASCII:
-    case BT_NMSTRT:
-#ifdef XML_NS
-    case BT_COLON:
-#endif
-    case BT_HEX:
-    case BT_DIGIT:
-    case BT_NAME:
-    case BT_MINUS:
-      ptr += MINBPC(enc);
-      break;
-    default:
-      return (int)(ptr - start);
-    }
-  }
-}
-
-static const char * PTRFASTCALL
-PREFIX(skipS)(const ENCODING *enc, const char *ptr)
-{
-  for (;;) {
-    switch (BYTE_TYPE(enc, ptr)) {
-    case BT_LF:
-    case BT_CR:
-    case BT_S:
-      ptr += MINBPC(enc);
-      break;
-    default:
-      return ptr;
-    }
-  }
-}
-
-static void PTRCALL
-PREFIX(updatePosition)(const ENCODING *enc,
-                       const char *ptr,
-                       const char *end,
-                       POSITION *pos)
-{
-  while (HAS_CHAR(enc, ptr, end)) {
-    switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
-    case BT_LEAD ## n: \
-      ptr += n; \
-      break;
-    LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
-    case BT_LF:
-      pos->columnNumber = (XML_Size)-1;
-      pos->lineNumber++;
-      ptr += MINBPC(enc);
-      break;
-    case BT_CR:
-      pos->lineNumber++;
-      ptr += MINBPC(enc);
-      if (HAS_CHAR(enc, ptr, end) && BYTE_TYPE(enc, ptr) == BT_LF)
-        ptr += MINBPC(enc);
-      pos->columnNumber = (XML_Size)-1;
-      break;
-    default:
-      ptr += MINBPC(enc);
-      break;
-    }
-    pos->columnNumber++;
-  }
-}
-
-#undef DO_LEAD_CASE
-#undef MULTIBYTE_CASES
-#undef INVALID_CASES
-#undef CHECK_NAME_CASE
-#undef CHECK_NAME_CASES
-#undef CHECK_NMSTRT_CASE
-#undef CHECK_NMSTRT_CASES
-
-#endif /* XML_TOK_IMPL_C */
diff --git a/components/expat/library/xmltok_ns.c b/components/expat/library/xmltok_ns.c
deleted file mode 100644 (file)
index c3b88fd..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-*/
-
-/* This file is included! */
-#ifdef XML_TOK_NS_C
-
-const ENCODING *
-NS(XmlGetUtf8InternalEncoding)(void)
-{
-  return &ns(internal_utf8_encoding).enc;
-}
-
-const ENCODING *
-NS(XmlGetUtf16InternalEncoding)(void)
-{
-#if BYTEORDER == 1234
-  return &ns(internal_little2_encoding).enc;
-#elif BYTEORDER == 4321
-  return &ns(internal_big2_encoding).enc;
-#else
-  const short n = 1;
-  return (*(const char *)&n
-          ? &ns(internal_little2_encoding).enc
-          : &ns(internal_big2_encoding).enc);
-#endif
-}
-
-static const ENCODING * const NS(encodings)[] = {
-  &ns(latin1_encoding).enc,
-  &ns(ascii_encoding).enc,
-  &ns(utf8_encoding).enc,
-  &ns(big2_encoding).enc,
-  &ns(big2_encoding).enc,
-  &ns(little2_encoding).enc,
-  &ns(utf8_encoding).enc /* NO_ENC */
-};
-
-static int PTRCALL
-NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
-                   const char **nextTokPtr)
-{
-  return initScan(NS(encodings), (const INIT_ENCODING *)enc,
-                  XML_PROLOG_STATE, ptr, end, nextTokPtr);
-}
-
-static int PTRCALL
-NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
-                    const char **nextTokPtr)
-{
-  return initScan(NS(encodings), (const INIT_ENCODING *)enc,
-                  XML_CONTENT_STATE, ptr, end, nextTokPtr);
-}
-
-int
-NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
-                    const char *name)
-{
-  int i = getEncodingIndex(name);
-  if (i == UNKNOWN_ENC)
-    return 0;
-  SET_INIT_ENC_INDEX(p, i);
-  p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog);
-  p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent);
-  p->initEnc.updatePosition = initUpdatePosition;
-  p->encPtr = encPtr;
-  *encPtr = &(p->initEnc);
-  return 1;
-}
-
-static const ENCODING *
-NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
-{
-#define ENCODING_MAX 128
-  char buf[ENCODING_MAX];
-  char *p = buf;
-  int i;
-  XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
-  if (ptr != end)
-    return 0;
-  *p = 0;
-  if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2)
-    return enc;
-  i = getEncodingIndex(buf);
-  if (i == UNKNOWN_ENC)
-    return 0;
-  return NS(encodings)[i];
-}
-
-int
-NS(XmlParseXmlDecl)(int isGeneralTextEntity,
-                    const ENCODING *enc,
-                    const char *ptr,
-                    const char *end,
-                    const char **badPtr,
-                    const char **versionPtr,
-                    const char **versionEndPtr,
-                    const char **encodingName,
-                    const ENCODING **encoding,
-                    int *standalone)
-{
-  return doParseXmlDecl(NS(findEncoding),
-                        isGeneralTextEntity,
-                        enc,
-                        ptr,
-                        end,
-                        badPtr,
-                        versionPtr,
-                        versionEndPtr,
-                        encodingName,
-                        encoding,
-                        standalone);
-}
-
-#endif /* XML_TOK_NS_C */
diff --git a/components/expat/port/chardata.c b/components/expat/port/chardata.c
deleted file mode 100644 (file)
index 012499b..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Copyright (c) 1998-2003 Thai Open Source Software Center Ltd
-   See the file COPYING for copying permission.
-
-   chardata.c
-*/
-
-#ifdef HAVE_EXPAT_CONFIG_H
-#include <expat_config.h>
-#endif
-#include "minicheck.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "chardata.h"
-
-
-static int
-xmlstrlen(const XML_Char *s)
-{
-    int len = 0;
-    assert(s != NULL);
-    while (s[len] != 0)
-        ++len;
-    return len;
-}
-
-
-void
-CharData_Init(CharData *storage)
-{
-    assert(storage != NULL);
-    storage->count = -1;
-}
-
-void
-CharData_AppendString(CharData *storage, const char *s)
-{
-    int maxchars = sizeof(storage->data) / sizeof(storage->data[0]);
-    int len;
-
-    assert(s != NULL);
-    len = strlen(s);
-    if (storage->count < 0)
-        storage->count = 0;
-    if ((len + storage->count) > maxchars) {
-        len = (maxchars - storage->count);
-    }
-    if (len + storage->count < (int)sizeof(storage->data)) {
-        memcpy(storage->data + storage->count, s, len);
-        storage->count += len;
-    }
-}
-
-void
-CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len)
-{
-    int maxchars;
-
-    assert(storage != NULL);
-    assert(s != NULL);
-    maxchars = sizeof(storage->data) / sizeof(storage->data[0]);
-    if (storage->count < 0)
-        storage->count = 0;
-    if (len < 0)
-        len = xmlstrlen(s);
-    if ((len + storage->count) > maxchars) {
-        len = (maxchars - storage->count);
-    }
-    if (len + storage->count < (int)sizeof(storage->data)) {
-        memcpy(storage->data + storage->count, s,
-               len * sizeof(storage->data[0]));
-        storage->count += len;
-    }
-}
-
-int
-CharData_CheckString(CharData *storage, const char *expected)
-{
-    char buffer[1280];
-    int len;
-    int count;
-
-    assert(storage != NULL);
-    assert(expected != NULL);
-    count = (storage->count < 0) ? 0 : storage->count;
-    len = strlen(expected);
-    if (len != count) {
-        if (sizeof(XML_Char) == 1)
-            sprintf(buffer, "wrong number of data characters:"
-                    " got %d, expected %d:\n%s", count, len, storage->data);
-        else
-            sprintf(buffer,
-                    "wrong number of data characters: got %d, expected %d",
-                    count, len);
-        fail(buffer);
-        return 0;
-    }
-    if (memcmp(expected, storage->data, len) != 0) {
-        fail("got bad data bytes");
-        return 0;
-    }
-    return 1;
-}
-
-int
-CharData_CheckXMLChars(CharData *storage, const XML_Char *expected)
-{
-    char buffer[1024];
-    int len = xmlstrlen(expected);
-    int count;
-
-    assert(storage != NULL);
-    count = (storage->count < 0) ? 0 : storage->count;
-    if (len != count) {
-        sprintf(buffer, "wrong number of data characters: got %d, expected %d",
-                count, len);
-        fail(buffer);
-        return 0;
-    }
-    if (memcmp(expected, storage->data, len * sizeof(storage->data[0])) != 0) {
-        fail("got bad data bytes");
-        return 0;
-    }
-    return 1;
-}
diff --git a/components/expat/port/expat_element.c b/components/expat/port/expat_element.c
deleted file mode 100644 (file)
index 1112518..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* This is simple demonstration of how to use expat. This program
-   reads an XML document from standard input and writes a line with
-   the name of each element to standard output indenting child
-   elements by one tab stop more than their parent element.
-   It must be used with Expat compiled for UTF-8 output.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "expat.h"
-
-#define XML_FMT_INT_MOD "l"
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  int i;
-  int *depthPtr = (int *)userData;
-  (void)atts;
-
-  for (i = 0; i < *depthPtr; i++)
-    putchar('\t');
-  puts(name);
-  *depthPtr += 1;
-}
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  int *depthPtr = (int *)userData;
-  (void)name;
-
-  *depthPtr -= 1;
-}
-
-int xml_main(int argc, const char *argv)
-{
-  char *buf = NULL;
-  int depth = 0;
-  if (argv == NULL){
-        printf("no element parse\n");
-        return 1;
-  }
-  
-  XML_Parser parser = XML_ParserCreate(NULL);
-  if (parser){
-         XML_SetUserData(parser, &depth);
-         XML_SetElementHandler(parser, startElement, endElement);
-         buf = (char*)malloc(argc + 1);
-         bzero(buf, argc + 1);
-         memcpy(buf, argv, argc);
-         if (XML_Parse(parser, buf, argc, 0) == XML_STATUS_ERROR) {
-             printf( "%s at line %" XML_FMT_INT_MOD "u\n",
-                     XML_ErrorString(XML_GetErrorCode(parser)),
-                     XML_GetCurrentLineNumber(parser));
-         }else{
-                 printf("XML_Parse Sucessful\n ");
-         }       
-  }
-
-  XML_ParserFree(parser);
-  return 0;
-}
-
diff --git a/components/expat/port/include/chardata.h b/components/expat/port/include/chardata.h
deleted file mode 100644 (file)
index e8dc4ce..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* chardata.h
-
-   Interface to some helper routines used to accumulate and check text
-   and attribute content.
-*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef XML_CHARDATA_H
-#define XML_CHARDATA_H 1
-
-#ifndef XML_VERSION
-#include "expat.h"                      /* need XML_Char */
-#endif
-
-
-typedef struct {
-    int count;                          /* # of chars, < 0 if not set */
-    XML_Char data[1024];
-} CharData;
-
-
-void CharData_Init(CharData *storage);
-
-void CharData_AppendString(CharData *storage, const char *s);
-
-void CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len);
-
-int CharData_CheckString(CharData *storage, const char *s);
-
-int CharData_CheckXMLChars(CharData *storage, const XML_Char *s);
-
-
-#endif  /* XML_CHARDATA_H */
-
-#ifdef __cplusplus
-}
-#endif
similarity index 91%
rename from components/expat/include/expat/expat_config.h
rename to components/expat/port/include/expat_config.h
index 207d1a7791dc53e55c19e6ad4eaa22f281b341dc..b6b927a19bb191cd4a4bf951807eb17e8017c65d 100644 (file)
@@ -3,7 +3,6 @@
 
 /* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
 #define BYTEORDER 1234
-
 /* Define to 1 if you have the `bcopy' function. */
 #define HAVE_BCOPY 1
 
@@ -15,7 +14,6 @@
 
 /* Define to 1 if you have the `getpagesize' function. */
 #define HAVE_GETPAGESIZE 1
-
 /* Define to 1 if you have the <inttypes.h> header file. */
 #define HAVE_INTTYPES_H 1
 
 /* Define to 1 if you have the <unistd.h> header file. */
 #define HAVE_UNISTD_H 1
 
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
-   */
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
 #define LT_OBJDIR ".libs/"
 
+/* Name of package */
+#define PACKAGE "expat"
+
 /* Define to the address where bug reports for this package should be sent. */
 #define PACKAGE_BUGREPORT "expat-bugs@libexpat.org"
 
@@ -63,7 +63,7 @@
 #define PACKAGE_NAME "expat"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "expat 2.2.0"
+#define PACKAGE_STRING "expat 2.2.5"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "expat"
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "2.2.0"
+#define PACKAGE_VERSION "2.2.5"
 
 /* Define to 1 if you have the ANSI C header files. */
 #define STDC_HEADERS 1
 
+/* Version number of package */
+#define VERSION "2.2.5"
+
 /* whether byteorder is bigendian */
 /* #undef WORDS_BIGENDIAN */
 
@@ -90,9 +93,6 @@
 /* Define to make XML Namespaces functionality available. */
 #define XML_NS 1
 
-/* Define to __FUNCTION__ or "" if `__func__' does not conform to ANSI C. */
-/* #undef __func__ */
-
 /* Define to empty if `const' does not conform to ANSI C. */
 /* #undef const */
 
diff --git a/components/expat/port/include/minicheck.h b/components/expat/port/include/minicheck.h
deleted file mode 100644 (file)
index d54801d..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Miniature re-implementation of the "check" library.
- *
- * This is intended to support just enough of check to run the Expat
- * tests.  This interface is based entirely on the portion of the
- * check library being used.
- *
- * This is *source* compatible, but not necessary *link* compatible.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define CK_NOFORK 0
-#define CK_FORK   1
-
-#define CK_SILENT  0
-#define CK_NORMAL  1
-#define CK_VERBOSE 2
-
-/* Workaround for Microsoft's compiler and Tru64 Unix systems where the
-   C compiler has a working __func__, but the C++ compiler only has a 
-   working __FUNCTION__.  This could be fixed in configure.in, but it's
-   not worth it right now. */
-#if defined (_MSC_VER) || (defined(__osf__) && defined(__cplusplus))
-#define __func__ __FUNCTION__
-#endif
-
-/* ISO C90 does not support '__func__' predefined identifier */
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901)
-# define __func__ "(unknown)"
-#endif
-
-#define START_TEST(testname) static void testname(void) { \
-    _check_set_test_info(__func__, __FILE__, __LINE__);   \
-    {
-#define END_TEST 
-
-#define fail(msg)  _fail_unless(0, __FILE__, __LINE__, msg)
-
-typedef void (*tcase_setup_function)(void);
-typedef void (*tcase_teardown_function)(void);
-typedef void (*tcase_test_function)(void);
-
-typedef struct SRunner SRunner;
-typedef struct Suite Suite;
-typedef struct TCase TCase;
-
-struct SRunner {
-    Suite *suite;
-    int nchecks;
-    int nfailures;
-};
-
-struct Suite {
-    const char *name;
-    TCase *tests;
-};
-
-struct TCase {
-    const char *name;
-    tcase_setup_function setup;
-    tcase_teardown_function teardown;
-    tcase_test_function *tests;
-    int ntests;
-    int allocated;
-    TCase *next_tcase;
-};
-
-
-/* Internal helper. */
-void _check_set_test_info(char const *function,
-                          char const *filename, int lineno);
-
-
-/*
- * Prototypes for the actual implementation.
- */
-
-void _fail_unless(int condition, const char *file, int line, const char *msg);
-Suite *suite_create(const char *name);
-TCase *tcase_create(const char *name);
-void suite_add_tcase(Suite *suite, TCase *tc);
-void tcase_add_checked_fixture(TCase *,
-                               tcase_setup_function,
-                               tcase_teardown_function);
-void tcase_add_test(TCase *tc, tcase_test_function test);
-SRunner *srunner_create(Suite *suite);
-void srunner_run_all(SRunner *runner, int verbosity);
-int srunner_ntests_failed(SRunner *runner);
-void srunner_free(SRunner *runner);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/components/expat/port/minicheck.c b/components/expat/port/minicheck.c
deleted file mode 100644 (file)
index 95a4939..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Miniature re-implementation of the "check" library.
- *
- * This is intended to support just enough of check to run the Expat
- * tests.  This interface is based entirely on the portion of the
- * check library being used.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <setjmp.h>
-#include <assert.h>
-
-#include "internal.h"  /* for UNUSED_P only */
-#include "minicheck.h"
-
-Suite *
-suite_create(const char *name)
-{
-    Suite *suite = (Suite *) calloc(1, sizeof(Suite));
-    if (suite != NULL) {
-        suite->name = name;
-    }
-    return suite;
-}
-
-TCase *
-tcase_create(const char *name)
-{
-    TCase *tc = (TCase *) calloc(1, sizeof(TCase));
-    if (tc != NULL) {
-        tc->name = name;
-    }
-    return tc;
-}
-
-void
-suite_add_tcase(Suite *suite, TCase *tc) 
-{
-    assert(suite != NULL);
-    assert(tc != NULL);
-    assert(tc->next_tcase == NULL);
-
-    tc->next_tcase = suite->tests;
-    suite->tests = tc;
-}
-
-void
-tcase_add_checked_fixture(TCase *tc,
-                          tcase_setup_function setup,
-                          tcase_teardown_function teardown)
-{
-    assert(tc != NULL);
-    tc->setup = setup;
-    tc->teardown = teardown;
-}
-
-void
-tcase_add_test(TCase *tc, tcase_test_function test)
-{
-    assert(tc != NULL);
-    if (tc->allocated == tc->ntests) {
-        int nalloc = tc->allocated + 100;
-        size_t new_size = sizeof(tcase_test_function) * nalloc;
-        tcase_test_function *new_tests = realloc(tc->tests, new_size);
-        assert(new_tests != NULL);
-        if (new_tests != tc->tests) {
-            free(tc->tests);
-            tc->tests = new_tests;
-        }
-        tc->allocated = nalloc;
-    }
-    tc->tests[tc->ntests] = test;
-    tc->ntests++;
-}
-
-SRunner *
-srunner_create(Suite *suite)
-{
-    SRunner *runner = calloc(1, sizeof(SRunner));
-    if (runner != NULL) {
-        runner->suite = suite;
-    }
-    return runner;
-}
-
-static jmp_buf env;
-
-static char const *_check_current_function = NULL;
-static int _check_current_lineno = -1;
-static char const *_check_current_filename = NULL;
-
-void
-_check_set_test_info(char const *function, char const *filename, int lineno)
-{
-    _check_current_function = function;
-    _check_current_lineno = lineno;
-    _check_current_filename = filename;
-}
-
-
-static void
-add_failure(SRunner *runner, int verbosity)
-{
-    runner->nfailures++;
-    if (verbosity >= CK_VERBOSE) {
-        printf("%s:%d: %s\n", _check_current_filename,
-               _check_current_lineno, _check_current_function);
-    }
-}
-
-static void run_test(SRunner *runner, int verbosity, TCase *tc, int i)
-{
-  if (tc->setup != NULL) {
-    /* setup */
-    if (setjmp(env)) {
-      add_failure(runner, verbosity);
-      return;
-    }
-    tc->setup();
-  }
-  /* test */
-  if (setjmp(env)) {
-    add_failure(runner, verbosity);
-    return;
-  }
-  (tc->tests[i])();
-
-  /* teardown */
-  if (tc->teardown != NULL) {
-    if (setjmp(env)) {
-      add_failure(runner, verbosity);
-      return;
-    }
-    tc->teardown();
-  }
-}
-
-void
-srunner_run_all(SRunner *runner, int verbosity)
-{
-    assert(runner != NULL);
-    assert(runner->suite != NULL);
-    TCase *tc = runner->suite->tests;
-    while (tc != NULL) {
-        for (int i = 0; i < tc->ntests; ++i) {
-            runner->nchecks++;
-            run_test(runner, verbosity, tc, i);
-            tc = tc->next_tcase;
-        }
-    }
-    if (verbosity) {
-        int passed = runner->nchecks - runner->nfailures;
-        double percentage = ((double) passed) / runner->nchecks;
-        int display = (int) (percentage * 100);
-        printf("%d%%: Checks: %d, Failed: %d\n",
-               display, runner->nchecks, runner->nfailures);
-    }
-}
-
-void
-_fail_unless(int UNUSED_P(condition), const char *UNUSED_P(file), int UNUSED_P(line), const char *msg)
-{
-    /* Always print the error message so it isn't lost.  In this case,
-       we have a failure, so there's no reason to be quiet about what
-       it is.
-    */
-    if (msg != NULL)
-        printf("%s", msg);
-    longjmp(env, 1);
-}
-
-int
-srunner_ntests_failed(SRunner *runner)
-{
-    assert(runner != NULL);
-    return runner->nfailures;
-}
-
-void
-srunner_free(SRunner *runner)
-{
-    free(runner->suite);
-    free(runner);
-}
diff --git a/components/expat/test/component.mk b/components/expat/test/component.mk
new file mode 100644 (file)
index 0000000..f985b1d
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Component Makefile
+#
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
diff --git a/components/expat/test/test_expat.c b/components/expat/test/test_expat.c
new file mode 100644 (file)
index 0000000..21c7cd0
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <expat.h>
+#include <string.h>
+#include "unity.h"
+
+typedef struct {
+    int depth;
+    char output[512];
+    int output_off;
+} user_data_t;
+
+static void insert_space(user_data_t *user_data)
+{
+    const char align_str[] = "    ";
+
+    TEST_ASSERT(sizeof(user_data->output) >= user_data->output_off);
+    user_data->output[user_data->output_off++] = '\n';
+
+    for (int i = 0; i < user_data->depth; i++) {
+        for (int j = 0; j < strlen(align_str); ++j) {
+            TEST_ASSERT(sizeof(user_data->output) >= user_data->output_off);
+            user_data->output[user_data->output_off++] = align_str[j];
+        }
+    }
+}
+
+static void XMLCALL start_element(void *userData, const XML_Char *name, const XML_Char **atts)
+{
+    user_data_t *user_data = (user_data_t *) userData;
+
+    insert_space(user_data);
+
+    const int ret = snprintf(user_data->output + user_data->output_off,
+            sizeof(user_data->output) - user_data->output_off,
+            "<%s>", name);
+    TEST_ASSERT_EQUAL(strlen(name) + 2, ret); // 2 are the tag characters: "<>"
+    user_data->output_off += ret;
+    ++user_data->depth;
+}
+
+static void XMLCALL end_element(void *userData, const XML_Char *name)
+{
+    user_data_t *user_data = (user_data_t *) userData;
+
+    --user_data->depth;
+    insert_space(user_data);
+
+    int ret = snprintf(user_data->output + user_data->output_off, sizeof(user_data->output) - user_data->output_off,
+                "</%s>", name);
+    TEST_ASSERT_EQUAL(strlen(name) + 3, ret); // 3 are the tag characters: "</>"
+    user_data->output_off += ret;
+}
+
+static void data_handler(void *userData, const XML_Char *s, int len)
+{
+    user_data_t *user_data = (user_data_t *) userData;
+
+    insert_space(user_data);
+
+    // s is not zero-terminated
+    char tmp_str[len+1];
+    strlcpy(tmp_str, s, len+1);
+
+    int ret = snprintf(user_data->output + user_data->output_off, sizeof(user_data->output) - user_data->output_off,
+                "%s", tmp_str);
+    TEST_ASSERT_EQUAL(strlen(tmp_str), ret);
+    user_data->output_off += ret;
+}
+
+TEST_CASE("Expat parses XML", "[expat]")
+{
+    const char test_in[] = "<html><title>Page title</title><body><h>header</h><ol><li>A</li>"\
+                           "<li>B</li><li>C</li></ol></body></html>";
+    const char test_expected[] =    "\n"\
+                                    "<html>\n"\
+                                    "    <title>\n"\
+                                    "        Page title\n"\
+                                    "    </title>\n"\
+                                    "    <body>\n"\
+                                    "        <h>\n"\
+                                    "            header\n"\
+                                    "        </h>\n"\
+                                    "        <ol>\n"\
+                                    "            <li>\n"\
+                                    "                A\n"\
+                                    "            </li>\n"\
+                                    "            <li>\n"\
+                                    "                B\n"\
+                                    "            </li>\n"\
+                                    "            <li>\n"\
+                                    "                C\n"\
+                                    "            </li>\n"\
+                                    "        </ol>\n"\
+                                    "    </body>\n"\
+                                    "</html>";
+    user_data_t user_data = {
+        .depth = 0,
+        .output = { '\0' },
+        .output_off = 0
+    };
+
+    XML_Parser parser = XML_ParserCreate(NULL);
+    XML_SetUserData(parser, &user_data);
+    XML_SetElementHandler(parser, start_element, end_element);
+    XML_SetCharacterDataHandler(parser, data_handler);
+
+    TEST_ASSERT_NOT_EQUAL(XML_STATUS_ERROR, XML_Parse(parser, test_in, strlen(test_in), 1));
+    XML_ParserFree(parser);
+
+    TEST_ASSERT_EQUAL(0, user_data.depth); // all closing tags have been found
+
+    TEST_ASSERT_EQUAL(strlen(test_expected), strlen(user_data.output));
+    TEST_ASSERT_EQUAL_STRING(test_expected, user_data.output);
+}
index d995d3f76e2bcc36aa961145ec1b73150e6b8d7d..40547906f0f619e1055660cae3223f62fc7bee1b 100644 (file)
@@ -115,3 +115,12 @@ BYTE ff_diskio_get_pdrv_wl(wl_handle_t flash_handle)
     }
     return 0xff;
 }
+
+void ff_diskio_clear_pdrv_wl(wl_handle_t flash_handle)
+{
+    for (int i = 0; i < FF_VOLUMES; i++) {
+        if (flash_handle == ff_wl_handles[i]) {
+            ff_wl_handles[i] = WL_INVALID_HANDLE;
+        }
+    }
+}
index 19d2c77daaf297cf0df1527ba35b6ee290ed07f9..9abff7ae06dc93777f82da9261086425f53e7143 100644 (file)
@@ -31,6 +31,7 @@ extern "C" {
  */
 esp_err_t ff_diskio_register_wl_partition(BYTE pdrv, wl_handle_t flash_handle);
 BYTE ff_diskio_get_pdrv_wl(wl_handle_t flash_handle);
+void ff_diskio_clear_pdrv_wl(wl_handle_t flash_handle);
 
 #ifdef __cplusplus
 }
index 15bbd61273d324cd137448d4025c78d7d62b595e..50bf9b4e1b5b66dbec59f2c6ecc484f1b3a146e7 100644 (file)
@@ -124,6 +124,7 @@ esp_err_t esp_vfs_fat_spiflash_unmount(const char *base_path, wl_handle_t wl_han
 
     f_mount(0, drv, 0);
     ff_diskio_unregister(pdrv);
+    ff_diskio_clear_pdrv_wl(wl_handle);
     // release partition driver
     esp_err_t err_drv = wl_unmount(wl_handle);
     esp_err_t err = esp_vfs_fat_unregister_path(base_path);
index c523c0e0ea8c3420ff46e89a9510c733f3b14d34..2ab31f087e1960e78229347c40fe528a1df23555 100644 (file)
@@ -214,6 +214,11 @@ TEST_CASE("(SD) mount two FAT partitions, SDMMC and WL, at the same time", "[fat
     const char* str_sd = "this is sd\n";
     const char* str_wl = "this is spiflash\n";
 
+    /* Erase flash before the firs use */
+    const esp_partition_t *test_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "flash_test");
+    esp_partition_erase_range(test_partition, 0, test_partition->size);
+    printf("Partition erased: addr- 0x%08x, size- 0x%08x\n", test_partition->address, test_partition->size);
+
     /* Mount FATFS in SD can WL at the same time. Create a file on each FS */
     wl_handle_t wl_handle = WL_INVALID_HANDLE;
     test_setup();
index 29bfbfc346a25b2addbefafe497e3c2c409d0aff..07a7ce9fe19a6fedb6888ce926b3f6b7e7a99a0d 100644 (file)
@@ -155,17 +155,15 @@ static inline void PORTMUX_RELEASE_MUX_FN_NAME(portMUX_TYPE *mux) {
 #endif
 
        assert(coreID == mux->owner); // This is a mutex we didn't lock, or it's corrupt
-       assert(mux->count > 0); // Indicates memory corruption
-       assert(mux->count < 0x100); // Indicates memory corruption
 
        mux->count--;
        if(mux->count == 0) {
                mux->owner = portMUX_FREE_VAL;
-       }
+       } else {
+               assert(mux->count < 0x100); // Indicates memory corruption
 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
-       else {
                ets_printf("Recursive unlock: count=%d last locked %s line %d, curr %s line %d\n", mux->count, lastLockedFn, lastLockedLine, fnName, line);
-       }
 #endif
+       }
 #endif //!CONFIG_FREERTOS_UNICORE
 }
index e5a273a0f15eb2a7de3cdae5813636646197b1da..90b8821f59043fc9d9107d047a84ee7d0997a39b 100644 (file)
@@ -75,9 +75,16 @@ IRAM_ATTR void *heap_caps_malloc( size_t size, uint32_t caps )
         if ((caps & MALLOC_CAP_8BIT) || (caps & MALLOC_CAP_DMA)) {
             return NULL;
         }
-        //If any, EXEC memory should be 32-bit aligned, so round up to the next multiple of 4.
+        caps |= MALLOC_CAP_32BIT; // IRAM is 32-bit accessible RAM
+    }
+
+    if (caps & MALLOC_CAP_32BIT) {
+        /* 32-bit accessible RAM should allocated in 4 byte aligned sizes
+         * (Future versions of ESP-IDF should possibly fail if an invalid size is requested)
+         */
         size = (size + 3) & (~3);
     }
+
     for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) {
         //Iterate over heaps and check capabilities at this priority
         heap_t *heap;
index a2b66bfc723f3b27a18554a9e4cafde8f1bfd921..af1e27df4a5c74af57cac27cf467c3f9de85fdad 100644 (file)
@@ -52,74 +52,21 @@ void heap_caps_enable_nonos_stack_heaps()
     }
 }
 
-//Modify regions array to disable the given range of memory.
-static void disable_mem_region(soc_memory_region_t *regions, intptr_t from, intptr_t to)
-{
-    //Align from and to on word boundaries
-    from = from & ~3;
-    to = (to + 3) & ~3;
-
-    for (int i = 0; i < soc_memory_region_count; i++) {
-        soc_memory_region_t *region = &regions[i];
-
-        intptr_t regStart = region->start;
-        intptr_t regEnd = region->start + region->size;
-        if (regStart >= from && regEnd <= to) {
-            //Entire region falls in the range. Disable entirely.
-            regions[i].type = -1;
-        } else if (regStart >= from && regEnd > to && regStart < to) {
-            //Start of the region falls in the range. Modify address/len.
-            intptr_t overlap = to - regStart;
-            region->start += overlap;
-            region->size -= overlap;
-            if (region->iram_address) {
-                region->iram_address += overlap;
-            }
-        } else if (regStart < from && regEnd > from && regEnd <= to) {
-            //End of the region falls in the range. Modify length.
-            region->size -= regEnd - from;
-        } else if (regStart < from && regEnd > to) {
-            //Range punches a hole in the region! We do not support this.
-            ESP_EARLY_LOGE(TAG, "region %d: hole punching is not supported!", i);
-            regions->type = -1; //Just disable memory region. That'll teach them!
-        }
-    }
-}
-
-/*
-Warning: These variables are assumed to have the start and end of the data and iram
-area used statically by the program, respectively. These variables are defined in the ld
-file.
-*/
-extern int _data_start, _heap_start, _init_start, _iram_text_end;
-
-/*
-Initialize the heap allocator. We pass it a bunch of region descriptors, but we need to modify those first to accommodate for
-the data as loaded by the bootloader.
-ToDo: The regions are different when stuff like trace memory, BT, ... is used. Modify the regions struct on the fly for this.
-Same with loading of apps. Same with using SPI RAM.
-*/
+/* Initialize the heap allocator to use all of the memory not
+   used by static data or reserved for other purposes
+ */
 void heap_caps_init()
 {
-    /* Copy the soc_memory_regions data to the stack, so we can
-       manipulate it. */
-    soc_memory_region_t regions[soc_memory_region_count];
-    memcpy(regions, soc_memory_regions, sizeof(soc_memory_region_t)*soc_memory_region_count);
-
-    //Disable the bits of memory where this code is loaded.
-    disable_mem_region(regions, (intptr_t)&_data_start, (intptr_t)&_heap_start);           //DRAM used by bss/data static variables
-    disable_mem_region(regions, (intptr_t)&_init_start, (intptr_t)&_iram_text_end);        //IRAM used by code
-
-    // Disable all regions reserved on this SoC
-    for (int i = 0; i < soc_reserved_region_count; i++) {
-        disable_mem_region(regions, soc_reserved_regions[i].start,
-                           soc_reserved_regions[i].end);
-    }
+    /* Get the array of regions that we can use for heaps
+       (with reserved memory removed already.)
+     */
+    size_t num_regions = soc_get_available_memory_region_max_count();
+    soc_memory_region_t regions[num_regions];
+    num_regions = soc_get_available_memory_regions(regions);
 
     //The heap allocator will treat every region given to it as separate. In order to get bigger ranges of contiguous memory,
     //it's useful to coalesce adjacent regions that have the same type.
-
-    for (int i = 1; i < soc_memory_region_count; i++) {
+    for (int i = 1; i < num_regions; i++) {
         soc_memory_region_t *a = &regions[i - 1];
         soc_memory_region_t *b = &regions[i];
         if (b->start == a->start + a->size && b->type == a->type ) {
@@ -131,7 +78,7 @@ void heap_caps_init()
 
     /* Count the heaps left after merging */
     size_t num_heaps = 0;
-    for (int i = 0; i < soc_memory_region_count; i++) {
+    for (int i = 0; i < num_regions; i++) {
         if (regions[i].type != -1) {
             num_heaps++;
         }
@@ -145,7 +92,7 @@ void heap_caps_init()
     size_t heap_idx = 0;
 
     ESP_EARLY_LOGI(TAG, "Initializing. RAM available for dynamic allocation:");
-    for (int i = 0; i < soc_memory_region_count; i++) {
+    for (int i = 0; i < num_regions; i++) {
         soc_memory_region_t *region = &regions[i];
         const soc_memory_type_desc_t *type = &soc_memory_types[region->type];
         heap_t *heap = &temp_heaps[heap_idx];
index 08b8caa21840b5217ca6475afd2c4959f6e02719..5573d5e5abb387945d2d1d9cf0e197110e2da305 100644 (file)
@@ -38,7 +38,7 @@ typedef enum {
  * @brief Trace record data type. Stores information about an allocated region of memory.
  */
 typedef struct {
-    uint32_t ccount; ///< CCOUNT of the CPU when the allocation was made. LSB (bit value 1) is the CPU number (0 or 1). */
+    uint32_t ccount; ///< CCOUNT of the CPU when the allocation was made. LSB (bit value 1) is the CPU number (0 or 1).
     void *address;   ///< Address which was allocated
     size_t size;     ///< Size of the allocation
     void *alloced_by[CONFIG_HEAP_TRACING_STACK_DEPTH]; ///< Call stack of the caller which allocated the memory.
index 435c31a5d8351dceef4f8461dd3726c3f949f48f..cbc431a2a3152a799b52700b94197fd25b42a93b 100644 (file)
@@ -593,7 +593,7 @@ test cases:
     - - P SSC1 C +DHCP:AP,OK
       - P SSC2 C +JAP:DISCONNECTED
   - - SSC SSC2 sta -D
-    - - R SSC2 C +JAP:DISCONNECTED
+    - - R SSC2 C OK
   - - SSC SSC1 dhcp -E -o 2
     - - R SSC1 C +DHCP:AP,OK
   - - SSC SSC1 dhcp -S -o 2
index 34d24635b5e7745445226a8aeb92fbe0164ec146..0f9bcd1f3fef1cfaaf19612e3ec63439d3187a55 100644 (file)
@@ -810,12 +810,6 @@ test cases:
     - - R PC_COM NC ERROR C +WIFICONN:OK
   - - SSC SSC2 sta -C -s <random_string> -p <random_string>
     - - R SSC2 RE JAP:DISCONNECTED,\d+,5
-  - - WIFI <pc_wifi_nic> DISCONN
-    - - P PC_COM C OK
-      - R SSC2 C +JAP:CONNECTED
-  - - SSC SSC1 ap -S -s <random_string> -p <random_string> -t 3 -m 1
-    - - P SSC1 C +SAP:OK
-      - P SSC2 RE JAP:DISCONNECTED,\d+,4
   execution time: 0.0
   expected result: |-
     1. succeed
@@ -823,8 +817,6 @@ test cases:
     3. succeed
     4. succeed
     5. disconnect event REASON_ASSOC_TOOMANY
-    6. succeed, target2 connect succeed
-    7. disconnect event REASON_ASSOC_EXPIRE
   initial condition: T2_1
   level: Integration
   module: WIFI MAC
@@ -834,11 +826,8 @@ test cases:
     3. target2 disconnect
     4. PC WIFI NIC connect to target1
     5. target2 connect to target1 with correct password
-    6. PC WIFI NIC disconnect
-    7. reconfig softap
   sub module: WIFI Connect
-  summary: test wifi disconnect reason REASON_ASSOC_TOOMANY, REASON_HANDSHAKE_TIMEOUT,
-    REASON_ASSOC_EXPIRE
+  summary: test wifi disconnect reason REASON_ASSOC_TOOMANY, REASON_HANDSHAKE_TIMEOUT
   test environment: SSC_T2_1
   test point 1: basic function
   test point 2: wifi disconnect reason test
index f1016f5c29915b005723056b58bac11280fa977c..89e08beb6e6c552ee703098e63d91da72fbd53c9 100644 (file)
@@ -1,5 +1,21 @@
 menu "mbedTLS"
 
+config MBEDTLS_PLATFORM_MEMORY
+   bool "Enable custom mbedTLS memory allocation layer."
+   default n
+   help
+      If this option is disabled, mbed TLS uses the default system
+      calloc() and free() functions.
+
+      If this option is enabled, the mbed TLS config macro
+      MBEDTLS_PLATFORM_MEMORY will be defined. The function
+      mbedtls_platform_set_calloc_free() must be called at
+      runtime to provide custom calloc() and free() function
+      pointers for use by mbedTLS.
+
+      This option allows fine-grained control over how mbedTLS
+      allocates heap memory.
+
 config MBEDTLS_SSL_MAX_CONTENT_LEN
     int "TLS maximum message content length"
     default 16384
index b3a48ac894b660f6b99dd10f01818fb6fc389b42..b9ada3067587aaccb37c33d41733bb82496c6342 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b3a48ac894b660f6b99dd10f01818fb6fc389b42
+Subproject commit b9ada3067587aaccb37c33d41733bb82496c6342
index c81bf1a06e2581d91014ce23f6cf9fa3979a549d..561ff723cf34c95d4bb3d5c97ded025694515910 100644 (file)
  *
  * Enable this layer to allow use of alternative memory allocators.
  */
-//#define MBEDTLS_PLATFORM_MEMORY
+#ifdef CONFIG_MBEDTLS_PLATFORM_MEMORY
+#define MBEDTLS_PLATFORM_MEMORY
+#endif
 
 /**
  * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
index 6ffebf663e04d79c63b969688d6acf7052cae222..09efde9836fb2e5d7265bdcfa93396feaa673be9 100644 (file)
@@ -1195,7 +1195,7 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed
         }
         if (service) {
             if (q->type == MDNS_TYPE_PTR || q->type == MDNS_TYPE_ANY) {
-                if (q->type == MDNS_TYPE_PTR) {
+                if (q->type == MDNS_TYPE_PTR || !parsed_packet->probe) {
                     shared = true;
                 }
                 if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service->service, false, false)
@@ -2570,7 +2570,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
                 continue;
             }
 
-            if (type == MDNS_TYPE_ANY) {
+            if (type == MDNS_TYPE_ANY && !_str_null_or_empty(name->host)) {
                 parsed_packet->probe = true;
             }
 
diff --git a/components/newlib/platform_include/sys/random.h b/components/newlib/platform_include/sys/random.h
new file mode 100644 (file)
index 0000000..afbf4df
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __SYS_RANDOM__
+#define __SYS_RANDOM__
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ssize_t getrandom(void *buf, size_t buflen, unsigned int flags);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //__SYS_RANDOM__
diff --git a/components/newlib/random.c b/components/newlib/random.c
new file mode 100644 (file)
index 0000000..47ebb23
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <sys/random.h>
+#include <sys/param.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include "esp_system.h"
+#include "esp_log.h"
+
+static const char *TAG = "RANDOM";
+
+ssize_t getrandom(void *buf, size_t buflen, unsigned int flags)
+{
+    // Flags are ignored because:
+    // - esp_random is non-blocking so it works for both blocking and non-blocking calls,
+    // - don't have opportunity so set som other source of entropy.
+
+    ESP_LOGD(TAG, "getrandom(buf=0x%x, buflen=%d, flags=%u)", (int) buf, buflen, flags);
+
+    if (buf == NULL) {
+        errno = EFAULT;
+        ESP_LOGD(TAG, "getrandom returns -1 (EFAULT)");
+        return -1;
+    }
+
+    uint8_t *dst = (uint8_t *) buf;
+    ssize_t ret = 0;
+
+    while (ret < buflen) {
+        const uint32_t random = esp_random();
+        const int needed = buflen - ret;
+        const int copy_len = MIN(sizeof(random), needed);
+        memcpy(dst + ret, &random, copy_len);
+        ret += copy_len;
+    }
+
+    ESP_LOGD(TAG, "getrandom returns %d", ret);
+    return ret;
+}
index d3563e247609d265402c2c9304ee470e3adf6a41..d1c06a472f5079e43db30436593d5a2e4e19e4a4 100644 (file)
@@ -68,7 +68,7 @@ int _system_r(struct _reent *r, const char *str)
     return -1;
 }
 
-void _raise_r(struct _reent *r)
+int _raise_r(struct _reent *r, int sig)
 {
     abort();
 }
index b3ba37fb4fc3cd4286f62a92163b2e7a45ef126b..44c6c7a2ca3a57a4bfa1dda14924ca040dfd64d1 100644 (file)
@@ -44,6 +44,7 @@ typedef uint32_t nvs_handle;
 #define ESP_ERR_NVS_NO_FREE_PAGES       (ESP_ERR_NVS_BASE + 0x0d)  /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */
 #define ESP_ERR_NVS_VALUE_TOO_LONG      (ESP_ERR_NVS_BASE + 0x0e)  /*!< String or blob length is longer than supported by the implementation */
 #define ESP_ERR_NVS_PART_NOT_FOUND      (ESP_ERR_NVS_BASE + 0x0f)  /*!< Partition with specified name is not found in the partition table */
+#define ESP_ERR_NVS_NEW_VERSION_FOUND   (ESP_ERR_NVS_BASE + 0x10)  /*!< NVS partition contains data in new format and cannot be recognized by this version of code */
 
 #define NVS_DEFAULT_PART_NAME           "nvs"   /*!< Default partition name of the NVS partition in the partition table */
 /**
index fb9cf3d40c404ae63ee7e035775be1bfe44239c1..73dabe8ea70f867232005f34fa68b14ed06d6d69 100644 (file)
@@ -64,6 +64,11 @@ esp_err_t Page::load(uint32_t sectorNumber)
     } else {
         mState = header.mState;
         mSeqNumber = header.mSeqNumber;
+        if(header.mVersion < NVS_VERSION) {
+            return ESP_ERR_NVS_NEW_VERSION_FOUND;
+        } else {
+            mVersion = header.mVersion;
+        }
     }
 
     switch (mState) {
@@ -633,6 +638,7 @@ esp_err_t Page::initialize()
     Header header;
     header.mState = mState;
     header.mSeqNumber = mSeqNumber;
+    header.mVersion = mVersion;
     header.mCrc32 = header.calculateCrc32();
 
     auto rc = spi_flash_write(mBaseAddress, &header, sizeof(header));
@@ -826,6 +832,15 @@ esp_err_t Page::setSeqNumber(uint32_t seqNumber)
     return ESP_OK;
 }
 
+esp_err_t Page::setVersion(uint8_t ver)
+{
+    if (mState != PageState::UNINITIALIZED) {
+        return ESP_ERR_NVS_INVALID_STATE;
+    }
+    mVersion = ver;
+    return ESP_OK;
+}
+
 esp_err_t Page::erase()
 {
     auto sector = mBaseAddress / SPI_FLASH_SEC_SIZE;
index ae803dede696740bb402d4eeafbedba5077c1dd2..e98deb22f5c76762b4abb6809a8cbd17307d66a6 100644 (file)
@@ -53,6 +53,8 @@ public:
 
     static const uint8_t CHUNK_ANY = Item::CHUNK_ANY;
 
+    static const uint8_t NVS_VERSION = 0xfe; // Decrement to upgrade
+
     enum class PageState : uint32_t {
         // All bits set, default state after flash erase. Page has not been initialized yet.
         UNINITIALIZED = 0xffffffff,
@@ -85,6 +87,8 @@ public:
     esp_err_t getSeqNumber(uint32_t& seqNumber) const;
 
     esp_err_t setSeqNumber(uint32_t seqNumber);
+    esp_err_t setVersion(uint8_t version);
 
     esp_err_t writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize, uint8_t chunkIdx = CHUNK_ANY);
 
@@ -144,12 +148,13 @@ protected:
     public:
         Header()
         {
-            std::fill_n(mReserved, sizeof(mReserved)/sizeof(mReserved[0]), UINT32_MAX);
+            std::fill_n(mReserved, sizeof(mReserved)/sizeof(mReserved[0]), UINT8_MAX);
         }
 
         PageState mState;       // page state
         uint32_t mSeqNumber;    // sequence number of this page
-        uint32_t mReserved[5];  // unused, must be 0xffffffff
+        uint8_t mVersion;       // nvs format version
+        uint8_t mReserved[19];  // unused, must be 0xff
         uint32_t mCrc32;        // crc of everything except mState
 
         uint32_t calculateCrc32();
@@ -200,6 +205,7 @@ protected:
     uint32_t mBaseAddress = 0;
     PageState mState = PageState::INVALID;
     uint32_t mSeqNumber = UINT32_MAX;
+    uint8_t mVersion = NVS_VERSION;
     typedef CompressedEnumTable<EntryState, 2, ENTRY_COUNT> TEntryTable;
     TEntryTable mEntryTable;
     size_t mNextFreeEntry = INVALID_ENTRY;
index 611973ce00cf55356bc97df0432632e382116e7b..461309771769aeb0d91e380c3ecbec6b5ef869f5 100644 (file)
@@ -236,10 +236,9 @@ esp_err_t Storage::writeMultiPageBlob(uint8_t nsIndex, const char* key, const vo
         for (auto it = std::begin(usedPages); it != std::end(usedPages); it++) {
             it->mPage->eraseItem(nsIndex, ItemType::BLOB_DATA, key, ii++);
         }
-        usedPages.clearAndFreeNodes();
-        return err;
     }
-    return ESP_OK;
+    usedPages.clearAndFreeNodes();
+    return err;
 }
 
 esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize)
index 32d5b2956a5fb3eb71ae1a5e830bc13e74b10898..0fc9b9501f452075b0d6a535d8810868e321e777 100644 (file)
@@ -9,6 +9,7 @@
 #include "esp_partition.h"
 #include "esp_log.h"
 #include <string.h>
+#include "esp_system.h"
 
 static const char* TAG = "test_nvs";
 
@@ -16,7 +17,7 @@ TEST_CASE("various nvs tests", "[nvs]")
 {
     nvs_handle handle_1;
     esp_err_t err = nvs_flash_init();
-    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err);
         const esp_partition_t* nvs_partition = esp_partition_find_first(
                 ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
@@ -83,7 +84,7 @@ TEST_CASE("calculate used and free space", "[nvs]")
     TEST_ASSERT_TRUE(h_count_entries == 0);
 
     esp_err_t err = nvs_flash_init();
-    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err);
         const esp_partition_t* nvs_partition = esp_partition_find_first(
                 ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
@@ -213,3 +214,28 @@ TEST_CASE("calculate used and free space", "[nvs]")
     TEST_ESP_OK(nvs_flash_erase());
     TEST_ESP_OK(nvs_flash_deinit());
 }
+
+TEST_CASE("check for memory leaks in nvs_set_blob", "[nvs]")
+{
+    esp_err_t err = nvs_flash_init();
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        err = nvs_flash_init();
+    }
+    TEST_ESP_OK( err );
+
+    for (int i = 0; i < 500; ++i) {
+        nvs_handle my_handle;
+        uint8_t key[20] = {0};
+
+        TEST_ESP_OK( nvs_open("test_namespace1", NVS_READWRITE, &my_handle) );
+        TEST_ESP_OK( nvs_set_blob(my_handle, "key", key, sizeof(key)) );
+        TEST_ESP_OK( nvs_commit(my_handle) );
+        nvs_close(my_handle);
+        printf("%d\n", esp_get_free_heap_size());
+    }
+
+    nvs_flash_deinit();
+    printf("%d\n", esp_get_free_heap_size());
+    /* heap leaks will be checked in unity_platform.c */
+}
index 4309f6d56118fe933b81d749285e762a3ddef4d8..411cb3ef82a7cd75d83db0a6ad017ae52c639ffa 100644 (file)
@@ -1710,6 +1710,20 @@ TEST_CASE("Check that orphaned blobs are erased during init", "[nvs]")
     TEST_ESP_OK(storage.writeItem(1, ItemType::BLOB, "key3", blob, sizeof(blob)));
 }
 
+
+TEST_CASE("Check for nvs version incompatibility", "[nvs]")
+{
+    SpiFlashEmulator emu(3);
+
+    int32_t val1 = 0x12345678;
+    Page p;
+    p.load(0);
+    TEST_ESP_OK(p.setVersion(Page::NVS_VERSION - 1));
+    TEST_ESP_OK(p.writeItem(1, ItemType::I32, "foo", &val1, sizeof(val1)));
+
+    TEST_ESP_ERR(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3), ESP_ERR_NVS_NEW_VERSION_FOUND);
+}
+
 TEST_CASE("Check that NVS supports old blob format without blob index", "[nvs]")
 {
     SpiFlashEmulator emu("../nvs_partition_generator/part_old_blob_format.bin");
index f50de7aafc8c9f8e2b7083d9fc1cab535e02ee58..0d0351f26bf5d8dd2518fae3d5b54c24cab8eb88 100644 (file)
@@ -45,7 +45,8 @@ config PARTITION_TABLE_OFFSET
 
         This number should be a multiple of 0x1000.
 
-        Note that partition offsets in the partition table CSV file may need to be changed if this value is set to a higher value.
+        Note that partition offsets in the partition table CSV file may need to be changed if this value is set to a higher value. To have
+        each partition offset adapt to the configured partition table offset, leave all partition offsets blank in the CSV file.
 
 config PARTITION_TABLE_MD5
     bool "Generate an MD5 checksum for the partition table"
index 2eefa2c9f4935a3684a90b0185ce11c687ab0c1a..7124559d3b27de4ce64d134ad068fb8252cfc026 100755 (executable)
@@ -96,19 +96,23 @@ class PartitionTable(list):
             if line.startswith("#") or len(line) == 0:
                 continue
             try:
-                res.append(PartitionDefinition.from_csv(line))
+                res.append(PartitionDefinition.from_csv(line, line_no+1))
             except InputError as e:
                 raise InputError("Error at line %d: %s" % (line_no+1, e))
             except Exception:
-                critical("Unexpected error parsing line %d: %s" % (line_no+1, line))
+                critical("Unexpected error parsing CSV line %d: %s" % (line_no+1, line))
                 raise
 
         # fix up missing offsets & negative sizes
         last_end = offset_part_table + PARTITION_TABLE_SIZE # first offset after partition table
         for e in res:
-            if offset_part_table != 0 and e.offset is not None and e.offset < last_end:
-                critical("WARNING: 0x%x address in the partition table is below 0x%x" % (e.offset, last_end))
-                e.offset = None
+            if e.offset is not None and e.offset < last_end:
+                if e == res[0]:
+                    raise InputError("CSV Error: First partition offset 0x%x overlaps end of partition table 0x%x"
+                                     % (e.offset, last_end))
+                else:
+                    raise InputError("CSV Error: Partitions overlap. Partition at line %d sets offset 0x%x. Previous partition ends 0x%x"
+                                     % (e.line_no, e.offset, last_end))
             if e.offset is None:
                 pad_to = 0x10000 if e.type == APP_TYPE else 4
                 if last_end % pad_to != 0:
@@ -246,12 +250,13 @@ class PartitionDefinition(object):
         self.encrypted = False
 
     @classmethod
-    def from_csv(cls, line):
+    def from_csv(cls, line, line_no):
         """ Parse a line from the CSV """
         line_w_defaults = line + ",,,,"  # lazy way to support default fields
         fields = [ f.strip() for f in line_w_defaults.split(",") ]
 
         res = PartitionDefinition()
+        res.line_no = line_no
         res.name = fields[0]
         res.type = res.parse_type(fields[1])
         res.subtype = res.parse_subtype(fields[2])
index 26b8591aac5716643ceba4eb145e3a0768b27b0a..22cf97bacb1987fd7712b97f486c57357f59fe5c 100644 (file)
@@ -1,5 +1,5 @@
 # Name,   Type, SubType, Offset,  Size, Flags
 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
-nvs,      data, nvs,     0x9000,  0x6000,
-phy_init, data, phy,     0xf000,  0x1000,
-factory,  app,  factory, 0x10000, 1M,
+nvs,      data, nvs,     ,        0x6000,
+phy_init, data, phy,     ,        0x1000,
+factory,  app,  factory, ,        1M,
index a9f12c0fd3d044beaec7a5603c5debbd282d37cd..8bcf89c20f5f58f9f1a650636990e33f05d1ac6c 100644 (file)
@@ -1,6 +1,6 @@
 # Name,   Type, SubType, Offset,  Size
 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
-nvs,      data, nvs,     0x9000,  0x6000
-phy_init, data, phy,     0xf000,  0x1000
-factory,  app,  factory, 0x10000, 1M
-coredump, data, coredump,,        64K
+nvs,      data, nvs,           ,  0x6000
+phy_init, data, phy,           ,  0x1000
+factory,  app,  factory,       ,  1M
+coredump, data, coredump,      ,  64K
index 0b14fdb4179023161cb56a4c1e9b4eb9d0f932bf..0a325b2f5a697bd2dcf393ec6021052c1dba6f34 100644 (file)
@@ -1,8 +1,8 @@
 # Name,   Type, SubType, Offset,   Size, Flags
 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
-nvs,      data, nvs,     0x9000,  0x4000
-otadata,  data, ota,     0xd000,  0x2000
-phy_init, data, phy,     0xf000,  0x1000
-factory,  app,  factory, 0x10000,  1M
-ota_0,    app,  ota_0,   ,         1M
-ota_1,    app,  ota_1,   ,         1M
+nvs,      data, nvs,     ,        0x4000,
+otadata,  data, ota,     ,        0x2000,
+phy_init, data, phy,     ,        0x1000,
+factory,  app,  factory, ,        1M,
+ota_0,    app,  ota_0,   ,        1M,
+ota_1,    app,  ota_1,   ,        1M,
index 64d70b0d8ebf76412daae9a96aa6602a31a423f5..3a2143690b4bc6195cc0cee0ace1055298332b47 100644 (file)
@@ -1,9 +1,9 @@
 # Name,   Type, SubType, Offset,   Size
 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
-nvs,      data, nvs,     0x9000,  0x4000
-otadata,  data, ota,     0xd000,  0x2000
-phy_init, data, phy,     0xf000,  0x1000
-factory,  0,    0,       0x10000,  1M
+nvs,      data, nvs,     ,         0x4000
+otadata,  data, ota,     ,         0x2000
+phy_init, data, phy,     ,         0x1000
+factory,  0,    0,       ,         1M
 coredump, data, coredump,,         64K
 ota_0,    0,    ota_0,   ,         1M
 ota_1,    0,    ota_1,   ,         1M
index 4bd619fc0bf77257b5f0309b6ef1718680d9922e..9f50f24652cffc31a7442c0c8ab865f1fd5e7ef4 100755 (executable)
@@ -162,8 +162,8 @@ second, data, 0x15,         ,  1M
 first, app, factory, 0x100000, 2M
 second, app, ota_0,  0x200000, 1M
 """
-        t = PartitionTable.from_csv(csv)
         with self.assertRaisesRegexp(InputError, "overlap"):
+            t = PartitionTable.from_csv(csv)
             t.verify()
 
 class BinaryOutputTests(unittest.TestCase):
index 5b3f81a465bcbcac7a76d97505687f9b788bc9ce..1c0f3d421802e9318c0c3c327106a133318aba5b 100644 (file)
@@ -1,5 +1,6 @@
 # currently the only SoC supported; to be moved into Kconfig
 SOC_NAME := esp32
 
-COMPONENT_SRCDIRS := $(SOC_NAME)
+COMPONENT_SRCDIRS := $(SOC_NAME) src/
+
 COMPONENT_ADD_INCLUDEDIRS := $(SOC_NAME)/include include
index 3ac5248c8e263e04b600cfb05e4dd10c600b3f04..59d171f3bcd4ef2eb2b87a5880386b9d45dc56b3 100644 (file)
 
 #ifndef __ASSEMBLER__
 #define BIT(nr)                 (1UL << (nr))
+#define BIT64(nr)               (1ULL << (nr))
 #else
 #define BIT(nr)                 (1 << (nr))
 #endif
diff --git a/components/soc/esp32/rtc_wdt.c b/components/soc/esp32/rtc_wdt.c
new file mode 100644 (file)
index 0000000..8daa352
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "soc/rtc_wdt.h"
+#include "soc/rtc.h"
+
+
+bool rtc_wdt_get_protect_status()
+{
+    return READ_PERI_REG(RTC_CNTL_WDTWPROTECT_REG) != RTC_CNTL_WDT_WKEY_VALUE;
+}
+
+void rtc_wdt_protect_off()
+{
+    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
+}
+
+void rtc_wdt_protect_on()
+{
+    WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
+}
+
+
+void rtc_wdt_enable()
+{
+    REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED);
+    SET_PERI_REG_MASK(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN | RTC_CNTL_WDT_PAUSE_IN_SLP);
+}
+
+void rtc_wdt_disable()
+{
+    bool protect = rtc_wdt_get_protect_status();
+    if (protect) {
+        rtc_wdt_protect_off();
+    }
+    REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED);
+    rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_OFF);
+    rtc_wdt_set_stage(RTC_WDT_STAGE1, RTC_WDT_STAGE_ACTION_OFF);
+    rtc_wdt_set_stage(RTC_WDT_STAGE2, RTC_WDT_STAGE_ACTION_OFF);
+    rtc_wdt_set_stage(RTC_WDT_STAGE3, RTC_WDT_STAGE_ACTION_OFF);
+    REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
+    REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
+    if (protect) {
+        rtc_wdt_protect_on();
+    }
+}
+
+void rtc_wdt_feed()
+{
+    bool protect = rtc_wdt_get_protect_status();
+    if (protect) {
+        rtc_wdt_protect_off();
+    }
+    REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED);
+    if (protect) {
+        rtc_wdt_protect_on();
+    }
+}
+
+esp_err_t rtc_wdt_set_time(rtc_wdt_stage_t stage, unsigned int timeout_ms)
+{
+    if (stage > 3) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    uint32_t timeout = rtc_clk_slow_freq_get_hz() * timeout_ms / 1000;
+    if (stage == RTC_WDT_STAGE0) {
+        WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, timeout);
+    } else if (stage == RTC_WDT_STAGE1) {
+        WRITE_PERI_REG(RTC_CNTL_WDTCONFIG2_REG, timeout);
+    } else if (stage == RTC_WDT_STAGE2) {
+        WRITE_PERI_REG(RTC_CNTL_WDTCONFIG3_REG, timeout);
+    } else {
+        WRITE_PERI_REG(RTC_CNTL_WDTCONFIG4_REG, timeout);
+    }
+
+    return ESP_OK;
+}
+
+esp_err_t rtc_wdt_set_stage(rtc_wdt_stage_t stage, rtc_wdt_stage_action_t stage_sel)
+{
+    if (stage > 3 || stage_sel > 4) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (stage == RTC_WDT_STAGE0) {
+        REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, stage_sel);
+    } else if (stage == RTC_WDT_STAGE1) {
+        REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG1, stage_sel);
+    } else if (stage == RTC_WDT_STAGE2) {
+        REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG2, stage_sel);
+    } else {
+        REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG3, stage_sel);
+    }
+
+    return ESP_OK;
+}
+
+esp_err_t rtc_wdt_set_length_of_reset_signal(rtc_wdt_reset_sig_t reset_src, rtc_wdt_length_sig_t reset_signal_length)
+{
+    if (reset_src > 1 || reset_signal_length > 7) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (reset_src == 0) {
+        REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, reset_signal_length);
+    } else {
+        REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, reset_signal_length);
+    }
+
+    return ESP_OK;
+}
+
+bool rtc_wdt_is_on()
+{
+    return (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN) != 0) || (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN) != 0);
+}
index 737216c84f06f185d7bfb115724b2c952f4043e0..e60fe83307c8f1f07aefe79abbb5e0ba65cf60e7 100644 (file)
@@ -60,8 +60,10 @@ const soc_memory_type_desc_t soc_memory_types[] = {
     { "PID5DRAM", { MALLOC_CAP_PID5|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_DEFAULT }, false, false},
     { "PID6DRAM", { MALLOC_CAP_PID6|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_DEFAULT }, false, false},
     { "PID7DRAM", { MALLOC_CAP_PID7|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_DEFAULT }, false, false},
+#ifdef CONFIG_SPIRAM_SUPPORT
     //Type 15: SPI SRAM data
     { "SPIRAM", { MALLOC_CAP_SPIRAM|MALLOC_CAP_DEFAULT, 0, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, false, false},
+#endif
 };
 
 const size_t soc_memory_type_count = sizeof(soc_memory_types)/sizeof(soc_memory_type_desc_t);
@@ -73,7 +75,9 @@ Because of requirements in the coalescing code which merges adjacent regions, th
 from low to high start address.
 */
 const soc_memory_region_t soc_memory_regions[] = {
+#ifdef CONFIG_SPIRAM_SUPPORT
     { 0x3F800000, 0x400000, 15, 0}, //SPI SRAM, if available
+#endif
     { 0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- used for rom code
     { 0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- if BT is enabled, used as BT HW shared memory
     { 0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- if BT is enabled, used data memory for BT ROM functions.
@@ -126,9 +130,8 @@ const size_t soc_memory_region_count = sizeof(soc_memory_regions)/sizeof(soc_mem
 
    These are removed from the soc_memory_regions array when heaps are created.
  */
-const soc_reserved_region_t soc_reserved_regions[] = {
-    { 0x40070000, 0x40078000 }, //CPU0 cache region
-    { 0x40078000, 0x40080000 }, //CPU1 cache region
+SOC_RESERVE_MEMORY_REGION(0x40070000, 0x40078000, cpu0_cache);
+SOC_RESERVE_MEMORY_REGION(0x40078000, 0x40080000, cpu1_cache);
 
     /* Warning: The ROM stack is located in the 0x3ffe0000 area. We do not specifically disable that area here because
        after the scheduler has started, the ROM stack is not used anymore by anything. We handle it instead by not allowing
@@ -146,27 +149,21 @@ const soc_reserved_region_t soc_reserved_regions[] = {
        list entries happen to end up in a region that is not touched by the stack; they can be placed safely there.
     */
 
-    { 0x3ffe0000, 0x3ffe0440 }, //Reserve ROM PRO data region
-    { 0x3ffe4000, 0x3ffe4350 }, //Reserve ROM APP data region
+SOC_RESERVE_MEMORY_REGION(0x3ffe0000, 0x3ffe0440, rom_pro_data); //Reserve ROM PRO data region
+SOC_RESERVE_MEMORY_REGION(0x3ffe4000, 0x3ffe4350, rom_app_data); //Reserve ROM APP data region
 
-#if CONFIG_BT_ENABLED
-    { 0x3ffb0000, 0x3ffc0000 }, //Reserve BT hardware shared memory & BT data region
-    { 0x3ffae000, 0x3ffaff10 }, //Reserve ROM data region, inc region needed for BT ROM routines
-#else
-    { 0x3ffae000, 0x3ffae6e0 }, //Reserve ROM data region
-#endif
+SOC_RESERVE_MEMORY_REGION(0x3ffae000, 0x3ffae6e0, rom_data);
 
 #if CONFIG_MEMMAP_TRACEMEM
 #if CONFIG_MEMMAP_TRACEMEM_TWOBANKS
-    { 0x3fff8000, 0x40000000 }, //Reserve trace mem region
+SOC_RESERVE_MEMORY_REGION(0x3fff8000, 0x40000000, trace_mem); //Reserve trace mem region
 #else
-    { 0x3fff8000, 0x3fffc000 }, //Reserve trace mem region
+SOC_RESERVE_MEMORY_REGION(0x3fff8000, 0x3fffc000, trace_mem); //Reserve trace mem region
 #endif
 #endif
 
-    { 0x3f800000, 0x3fC00000 }, //SPI RAM gets added later if needed, in spiram.c; reserve it for now
-};
-
-const size_t soc_reserved_region_count = sizeof(soc_reserved_regions)/sizeof(soc_reserved_region_t);
-
+#ifdef CONFIG_SPIRAM_SUPPORT
+SOC_RESERVE_MEMORY_REGION(0x3f800000, 0x3fC00000, spi_ram); //SPI RAM gets added later if needed, in spiram.c; reserve it for now
 #endif
+
+#endif /* BOOTLOADER_BUILD */
diff --git a/components/soc/include/soc/rtc_wdt.h b/components/soc/include/soc/rtc_wdt.h
new file mode 100644 (file)
index 0000000..9094a30
--- /dev/null
@@ -0,0 +1,181 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/* Recommendation of using API RTC_WDT.
+1) Setting and enabling rtc_wdt:
+@code
+    rtc_wdt_protect_off();
+    rtc_wdt_disable();
+    rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us);
+    rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_SYSTEM); //RTC_WDT_STAGE_ACTION_RESET_SYSTEM or RTC_WDT_STAGE_ACTION_RESET_RTC
+    rtc_wdt_set_time(RTC_WDT_STAGE0, 7000);     // timeout rtd_wdt 7000ms.
+    rtc_wdt_enable();
+    rtc_wdt_protect_on();
+ @endcode
+
+* If you use this option RTC_WDT_STAGE_ACTION_RESET_SYSTEM then after reset you can see these messages.
+They can help to understand where the CPUs were when the WDT was triggered.
+    W (30) boot: PRO CPU has been reset by WDT.
+       W (30) boot: WDT reset info: PRO CPU PC=0x400xxxxx
+       ... function where it happened
+
+       W (31) boot: WDT reset info: APP CPU PC=0x400xxxxx
+       ... function where it happened
+
+* If you use this option RTC_WDT_STAGE_ACTION_RESET_RTC then you will see message (rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)) 
+without description where were CPUs when it happened.
+
+2) Reset counter of rtc_wdt:
+@code
+    rtc_wdt_feed();
+@endcode
+
+3) Disable rtc_wdt:
+@code
+    rtc_wdt_disable();
+@endcode
+ */
+
+#ifndef _SOC_RTC_WDT_H
+#define _SOC_RTC_WDT_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "soc/rtc_cntl_reg.h"
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/// List of stage of rtc watchdog. WDT has 4 stage.
+typedef enum {
+    RTC_WDT_STAGE0 = 0,     /*!< Stage 0 */
+    RTC_WDT_STAGE1 = 1,     /*!< Stage 1 */
+    RTC_WDT_STAGE2 = 2,     /*!< Stage 2 */
+    RTC_WDT_STAGE3 = 3      /*!< Stage 3 */
+} rtc_wdt_stage_t;
+
+/// List of action. When the time of stage expires this action will be triggered.
+typedef enum {
+    RTC_WDT_STAGE_ACTION_OFF            = RTC_WDT_STG_SEL_OFF,          /*!< Disabled. This stage will have no effects on the system. */
+    RTC_WDT_STAGE_ACTION_INTERRUPT      = RTC_WDT_STG_SEL_INT,          /*!< Trigger an interrupt. When the stage expires an interrupt is triggered. */
+    RTC_WDT_STAGE_ACTION_RESET_CPU      = RTC_WDT_STG_SEL_RESET_CPU,    /*!< Reset a CPU core. */
+    RTC_WDT_STAGE_ACTION_RESET_SYSTEM   = RTC_WDT_STG_SEL_RESET_SYSTEM, /*!< Reset the main system includes the CPU and all peripherals. The RTC is an exception to this, and it will not be reset. */
+    RTC_WDT_STAGE_ACTION_RESET_RTC      = RTC_WDT_STG_SEL_RESET_RTC     /*!< Reset the main system and the RTC. */
+} rtc_wdt_stage_action_t;
+
+/// Type of reset signal
+typedef enum {
+    RTC_WDT_SYS_RESET_SIG = 0,     /*!< System reset signal length selection */
+    RTC_WDT_CPU_RESET_SIG = 1      /*!< CPU reset signal length selection */
+} rtc_wdt_reset_sig_t;
+
+/// Length of reset signal
+typedef enum {
+    RTC_WDT_LENGTH_100ns = 0,     /*!< 100 ns */
+    RTC_WDT_LENGTH_200ns = 1,     /*!< 200 ns */
+    RTC_WDT_LENGTH_300ns = 2,     /*!< 300 ns */
+    RTC_WDT_LENGTH_400ns = 3,     /*!< 400 ns */
+    RTC_WDT_LENGTH_500ns = 4,     /*!< 500 ns */
+    RTC_WDT_LENGTH_800ns = 5,     /*!< 800 ns */
+    RTC_WDT_LENGTH_1_6us = 6,     /*!< 1.6 us */
+    RTC_WDT_LENGTH_3_2us = 7      /*!< 3.2 us */
+} rtc_wdt_length_sig_t;
+
+/**
+ * @brief Get status of protect of rtc_wdt.
+ *
+ * @return
+ *         - True if the protect of RTC_WDT is set
+ */
+bool rtc_wdt_get_protect_status();
+
+/**
+ * @brief Set protect of rtc_wdt.
+ */
+void rtc_wdt_protect_on();
+
+/**
+ * @brief Reset protect of rtc_wdt.
+ */
+void rtc_wdt_protect_off();
+
+/**
+ * @brief Enable rtc_wdt.
+ */
+void rtc_wdt_enable();
+
+/**
+ * @brief Disable rtc_wdt.
+ */
+void rtc_wdt_disable();
+
+/**
+ * @brief Reset counter rtc_wdt.
+ *
+ * It returns to stage 0 and its expiry counter restarts from 0.
+ */
+void rtc_wdt_feed();
+
+/**
+ * @brief Set time for required stage.
+ *
+ * @param[in] stage Stage of rtc_wdt.
+ * @param[in] timeout_ms Timeout for this stage.
+ *
+ * @return
+ *         - ESP_OK In case of success
+ *         - ESP_ERR_INVALID_ARG If stage has invalid value
+ */
+esp_err_t rtc_wdt_set_time(rtc_wdt_stage_t stage, unsigned int timeout_ms);
+
+/**
+ * @brief Set an action for required stage.
+ *
+ * @param[in] stage Stage of rtc_wdt.
+ * @param[in] stage_sel Action for this stage. When the time of stage expires this action will be triggered.
+ *
+ * @return
+ *         - ESP_OK In case of success
+ *         - ESP_ERR_INVALID_ARG If stage or stage_sel have invalid value
+ */
+esp_err_t rtc_wdt_set_stage(rtc_wdt_stage_t stage, rtc_wdt_stage_action_t stage_sel);
+
+/**
+ * @brief Set a length of reset signal.
+ *
+ * @param[in] reset_src Type of reset signal.
+ * @param[in] reset_signal_length A length of reset signal.
+ *
+ * @return
+ *         - ESP_OK In case of success
+ *         - ESP_ERR_INVALID_ARG If reset_src  or reset_signal_length have invalid value
+ */
+esp_err_t rtc_wdt_set_length_of_reset_signal(rtc_wdt_reset_sig_t reset_src, rtc_wdt_length_sig_t reset_signal_length);
+
+/**
+ * @brief Return true if rtc_wdt is enabled.
+ *
+ * @return
+ *         - True rtc_wdt is enabled
+ */
+bool rtc_wdt_is_on();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _SOC_RTC_WDT_H
index 6273b1dbc32a61b63c0a66b873ca7b1bdad1b455..65382ba97f5f967ff855d0bfb690acb92b53ce0e 100644 (file)
@@ -57,8 +57,55 @@ typedef struct
     intptr_t end;
 } soc_reserved_region_t;
 
-extern const soc_reserved_region_t soc_reserved_regions[];
-extern const size_t soc_reserved_region_count;
+/* Use this macro to reserved a fixed region of RAM (hardcoded addresses)
+ * for a particular purpose.
+ *
+ * Usually used to mark out memory addresses needed for hardware or ROM code
+ * purposes.
+ *
+ * Don't call this macro from user code which can use normal C static allocation
+ * instead.
+ *
+ * @param START Start address to be reserved.
+ * @param END One after the address of the last byte to be reserved. (ie length of
+ * the reserved region is (END - START) in bytes.
+ * @param NAME Name for the reserved region. Must be a valid variable name,
+ * unique to this source file.
+ */
+#define SOC_RESERVE_MEMORY_REGION(START, END, NAME)     \
+    __attribute__((section(".reserved_memory_address"))) __attribute__((used)) \
+    static soc_reserved_region_t reserved_region_##NAME = { START, END };
+
+/* Return available memory regions for this SoC. Each available memory
+ * region is a contiguous piece of memory which is not being used by
+ * static data, used by ROM code, or reserved by a component using
+ * the SOC_RESERVE_MEMORY_REGION() macro.
+ *
+ * This result is soc_memory_regions[] minus all regions reserved
+ * via the SOC_RESERVE_MEMORY_REGION() macro (which may also split
+ * some regions up.)
+ *
+ * At startup, all available memory returned by this function is
+ * registered as heap space.
+ *
+ * @note OS-level startup function only, not recommended to call from
+ * app code.
+ *
+ * @param regions Pointer to an array for reading available regions into.
+ * Size of the array should be at least the result of
+ * soc_get_available_memory_region_max_count(). Entries in the array
+ * will be ordered by memory address.
+ *
+ * @return Number of entries copied to 'regions'. Will be no greater than
+ * the result of soc_get_available_memory_region_max_count().
+ */
+size_t soc_get_available_memory_regions(soc_memory_region_t *regions);
+
+/* Return the maximum number of available memory regions which could be
+ * returned by soc_get_available_memory_regions(). Used to size the
+ * array passed to that function.
+ */
+size_t soc_get_available_memory_region_max_count();
 
 inline static bool IRAM_ATTR esp_ptr_dma_capable(const void *p)
 {
diff --git a/components/soc/src/memory_layout_utils.c b/components/soc/src/memory_layout_utils.c
new file mode 100644 (file)
index 0000000..c1abc98
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <stdint.h>
+#include <string.h>
+#include "esp_log.h"
+#include "soc/soc_memory_layout.h"
+
+static const char *TAG = "memory_layout";
+
+/* These variables come from the linker script,
+   delimit the start and end of entries created via
+   SOC_RESERVE_MEMORY_REGION() macro.
+*/
+extern soc_reserved_region_t soc_reserved_memory_region_start;
+extern soc_reserved_region_t soc_reserved_memory_region_end;
+
+/*
+These variables have the start and end of the data and static IRAM
+area used by the program. Defined in the linker script.
+*/
+extern int _data_start, _bss_end, _iram_start, _iram_end;
+
+/* static DRAM & IRAM chunks */
+static const size_t EXTRA_RESERVED_REGIONS = 2;
+
+static size_t s_get_num_reserved_regions()
+{
+    return ( ( &soc_reserved_memory_region_end
+               - &soc_reserved_memory_region_start ) +
+             EXTRA_RESERVED_REGIONS );
+}
+
+size_t soc_get_available_memory_region_max_count()
+{
+    /* Worst-case: each reserved memory region splits an available
+       region in two, so the maximum possible number of regions
+       is the number of regions of memory plus the number of reservations */
+    return soc_memory_region_count + s_get_num_reserved_regions();
+}
+
+static int s_compare_reserved_regions(const void *a, const void *b)
+{
+    const soc_reserved_region_t *r_a = (soc_reserved_region_t *)a;
+    const soc_reserved_region_t *r_b = (soc_reserved_region_t *)b;
+    return (int)r_a->start - (int)r_b->start;
+}
+
+/* Initialize a mutable array of reserved regions in 'reserved',
+   then sort it by start address and check for overlapping
+   reserved regions (illegal).
+*/
+static void s_prepare_reserved_regions(soc_reserved_region_t *reserved, size_t count)
+{
+    memcpy(reserved + EXTRA_RESERVED_REGIONS,
+           &soc_reserved_memory_region_start,
+           (count - EXTRA_RESERVED_REGIONS) * sizeof(soc_reserved_region_t));
+
+    /* Add the EXTRA_RESERVED_REGIONS at the beginning */
+    reserved[0].start = (intptr_t)&_data_start; /* DRAM used by data+bss */
+    reserved[0].end = (intptr_t)&_bss_end;
+    reserved[1].start = (intptr_t)&_iram_start; /* IRAM used by code */
+    reserved[1].end = (intptr_t)&_iram_end;
+
+    /* Sort by starting address */
+    qsort(reserved, count, sizeof(soc_reserved_region_t), s_compare_reserved_regions);
+
+    /* Validity checks */
+    ESP_EARLY_LOGV(TAG, "reserved range is %p - %p",
+                   &soc_reserved_memory_region_start,
+                   &soc_reserved_memory_region_end);
+    ESP_EARLY_LOGD(TAG, "Checking %d reserved memory ranges:", count);
+    for (size_t i = 0; i < count; i++)
+    {
+        ESP_EARLY_LOGD(TAG, "Reserved memory range 0x%08x - 0x%08x",
+                       reserved[i].start, reserved[i].end);
+        reserved[i].start = reserved[i].start & ~3; /* expand all reserved areas to word boundaries */
+        reserved[i].end = (reserved[i].end + 3) & ~3;
+        assert(reserved[i].start < reserved[i].end);
+        if (i < count - 1) {
+            assert(reserved[i+1].start > reserved[i].start);
+            if (reserved[i].end > reserved[i+1].start) {
+                ESP_EARLY_LOGE(TAG, "SOC_RESERVE_MEMORY_REGION region range " \
+                               "0x%08x - 0x%08x overlaps with 0x%08x - 0x%08x",
+                               reserved[i].start, reserved[i].end, reserved[i+1].start,
+                               reserved[i+1].end);
+                abort();
+            }
+        }
+    }
+}
+
+size_t soc_get_available_memory_regions(soc_memory_region_t *regions)
+{
+    soc_memory_region_t *out_region = regions;
+    /* make a local copy of the "input" regions so we can modify them */
+    soc_memory_region_t in_regions[soc_memory_region_count];
+    memcpy(in_regions, soc_memory_regions, sizeof(in_regions));
+    soc_memory_region_t *in_region = in_regions;
+
+    size_t num_reserved = s_get_num_reserved_regions();
+    soc_reserved_region_t reserved[num_reserved];
+
+    s_prepare_reserved_regions(reserved, num_reserved);
+
+    /* Go through the "in" regions (full regions, with no reserved
+       sections removed from them) one at a time, trim off each reserved
+       region, and then copy them to an out_region once trimmed
+    */
+    ESP_EARLY_LOGD(TAG, "Building list of available memory regions:");
+    while(in_region != in_regions + soc_memory_region_count) {
+        soc_memory_region_t in = *in_region;
+        ESP_EARLY_LOGV(TAG, "Examining memory region 0x%08x - 0x%08x", in.start, in.start + in.size);
+        intptr_t in_start = in.start;
+        intptr_t in_end = in_start + in.size;
+        bool copy_in_to_out = true;
+        bool move_to_next = true;
+
+        for (size_t i = 0; i < num_reserved; i++) {
+            if (reserved[i].end <= in_start) {
+                /* reserved region ends before 'in' starts */
+                continue;
+            }
+            else if (reserved[i].start >= in_end) {
+                /* reserved region starts after 'in' ends */
+                break;
+            }
+            else if (reserved[i].start <= in_start &&
+                     reserved[i].end >= in_end) { /* reserved covers all of 'in' */
+                ESP_EARLY_LOGV(TAG, "Region 0x%08x - 0x%08x inside of reserved 0x%08x - 0x%08x",
+                               in_start, in_end, reserved[i].start, reserved[i].end);
+                /* skip 'in' entirely */
+                copy_in_to_out = false;
+                break;
+            }
+            else if (in_start < reserved[i].start &&
+                     in_end > reserved[i].end) { /* reserved contained inside 'in', need to "hole punch" */
+                ESP_EARLY_LOGV(TAG, "Region 0x%08x - 0x%08x contains reserved 0x%08x - 0x%08x",
+                               in_start, in_end, reserved[i].start, reserved[i].end);
+                assert(in_start < reserved[i].start);
+                assert(in_end > reserved[i].end);
+
+                /* shrink this region to end where the reserved section starts */
+                in_end = reserved[i].start;
+                in.size = in_end - in_start;
+
+                /* update in_region so the 'next' iteration uses the region
+                   after the reserved section */
+                in_region->size -= (reserved[i].end - in_region->start);
+                in_region->start = reserved[i].end;
+
+                /* add first region, then re-run while loop with the updated in_region */
+                move_to_next = false;
+                break;
+            }
+            else if (reserved[i].start <= in_start) { /* reserved overlaps start of 'in' */
+                ESP_EARLY_LOGV(TAG, "Start of region 0x%08x - 0x%08x overlaps reserved 0x%08x - 0x%08x",
+                               in_start, in_end, reserved[i].start, reserved[i].end);
+                in.start = reserved[i].end;
+                in_start = in.start;
+                in.size = in_end - in_start;
+            }
+            else { /* reserved overlaps end of 'in' */
+                ESP_EARLY_LOGV(TAG, "End of region 0x%08x - 0x%08x overlaps reserved 0x%08x - 0x%08x",
+                               in_start, in_end, reserved[i].start, reserved[i].end);
+                in_end = reserved[i].start;
+                in.size = in_end - in_start;
+            }
+        }
+
+        if (copy_in_to_out) {
+            ESP_EARLY_LOGD(TAG, "Available memory region 0x%08x - 0x%08x", in.start, in.start + in.size);
+            *out_region++ = in;
+        }
+        if (move_to_next) {
+            in_region++;
+        }
+    }
+
+    return (out_region - regions); /* return number of regions */
+}
index 43fdf6ccd4c1cb140ecd0880248fa50612426d28..f4249799dc653c5ab34beef68388d83be1fdd8d3 100644 (file)
@@ -127,20 +127,20 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_
     // region which should be mapped
     int phys_page = src_addr / SPI_FLASH_MMU_PAGE_SIZE;
     int page_count = (size + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE;
-    //prepare a linear pages array to feed into spi_flash_mmap_pages
-    int *pages=malloc(sizeof(int)*page_count);
-    if (pages==NULL) {
+    // prepare a linear pages array to feed into spi_flash_mmap_pages
+    int *pages = heap_caps_malloc(sizeof(int)*page_count, MALLOC_CAP_INTERNAL);
+    if (pages == NULL) {
         return ESP_ERR_NO_MEM;
     }
     for (int i = 0; i < page_count; i++) {
         pages[i] = phys_page+i;
     }
-    ret=spi_flash_mmap_pages(pages, page_count, memory, out_ptr, out_handle);
+    ret = spi_flash_mmap_pages(pages, page_count, memory, out_ptr, out_handle);
     free(pages);
     return ret;
 }
 
-esp_err_t IRAM_ATTR spi_flash_mmap_pages(int *pages, size_t page_count, spi_flash_mmap_memory_t memory,
+esp_err_t IRAM_ATTR spi_flash_mmap_pages(const int *pages, size_t page_count, spi_flash_mmap_memory_t memory,
                          const void** out_ptr, spi_flash_mmap_handle_t* out_handle)
 {
     esp_err_t ret;
@@ -148,6 +148,9 @@ esp_err_t IRAM_ATTR spi_flash_mmap_pages(int *pages, size_t page_count, spi_flas
     if (!page_count) {
         return ESP_ERR_INVALID_ARG;
     }
+    if (!esp_ptr_internal(pages)) {
+        return ESP_ERR_INVALID_ARG;
+    }
     for (int i = 0; i < page_count; i++) {
         if (pages[i] < 0 || pages[i]*SPI_FLASH_MMU_PAGE_SIZE >= g_rom_flashchip.chip_size) {
             return ESP_ERR_INVALID_ARG;
index f3d5a424af21f0398e85f741de78a3206b0d701a..5345fa97d164a2dc4ca8ca069f82c7e99a4c5bc0 100644 (file)
@@ -286,6 +286,37 @@ esp_err_t esp_partition_mmap(const esp_partition_t* partition, uint32_t offset,
                              spi_flash_mmap_memory_t memory,
                              const void** out_ptr, spi_flash_mmap_handle_t* out_handle);
 
+/**
+ * @brief Get SHA-256 digest for required partition.
+ *
+ * For apps with SHA-256 appended to the app image, the result is the appended SHA-256 value for the app image content.
+ * The hash is verified before returning, if app content is invalid then the function returns ESP_ERR_IMAGE_INVALID.
+ * For apps without SHA-256 appended to the image, the result is the SHA-256 of all bytes in the app image.
+ * For other partition types, the result is the SHA-256 of the entire partition.
+ *
+ * @param[in]  partition    Pointer to info for partition containing app or data. (fields: address, size and type, are required to be filled).
+ * @param[out] sha_256      Returned SHA-256 digest for a given partition.
+ *
+ * @return
+ *          - ESP_OK: In case of successful operation.
+ *          - ESP_ERR_INVALID_ARG: The size was 0 or the sha_256 was NULL.
+ *          - ESP_ERR_NO_MEM: Cannot allocate memory for sha256 operation.
+ *          - ESP_ERR_IMAGE_INVALID: App partition doesn't contain a valid app image.
+ *          - ESP_FAIL: An allocation error occurred.
+ */
+esp_err_t esp_partition_get_sha256(const esp_partition_t *partition, uint8_t *sha_256);
+
+/**
+ * @brief Check for the identity of two partitions by SHA-256 digest.
+ *
+ * @param[in] partition_1 Pointer to info for partition 1 containing app or data. (fields: address, size and type, are required to be filled).
+ * @param[in] partition_2 Pointer to info for partition 2 containing app or data. (fields: address, size and type, are required to be filled).
+ *
+ * @return
+ *         - True:  In case of the two firmware is equal.
+ *         - False: Otherwise
+ */
+bool esp_partition_check_identity(const esp_partition_t *partition_1, const esp_partition_t *partition_2);
 
 #ifdef __cplusplus
 }
index 9caa47e4085ea6c770fae3df135982e1bad38fd6..7977e116fed87f70a42fad5f36f6ad0809882cf5 100644 (file)
@@ -185,8 +185,8 @@ typedef uint32_t spi_flash_mmap_handle_t;
  * @param size  Size of region to be mapped. This size will be rounded
  *              up to a 64kB boundary
  * @param memory  Address space where the region should be mapped (data or instruction)
- * @param out_ptr  Output, pointer to the mapped memory region
- * @param out_handle  Output, handle which should be used for spi_flash_munmap call
+ * @param[out] out_ptr  Output, pointer to the mapped memory region
+ * @param[out] out_handle  Output, handle which should be used for spi_flash_munmap call
  *
  * @return  ESP_OK on success, ESP_ERR_NO_MEM if pages can not be allocated
  */
@@ -204,14 +204,19 @@ esp_err_t spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t m
  * @param pages An array of numbers indicating the 64kB pages in flash to be mapped
  *              contiguously into memory. These indicate the indexes of the 64kB pages,
  *              not the byte-size addresses as used in other functions.
- * @param pagecount  Number of entries in the pages array
+ *              Array must be located in internal memory.
+ * @param page_count  Number of entries in the pages array
  * @param memory  Address space where the region should be mapped (instruction or data)
- * @param out_ptr  Output, pointer to the mapped memory region
- * @param out_handle  Output, handle which should be used for spi_flash_munmap call
+ * @param[out] out_ptr  Output, pointer to the mapped memory region
+ * @param[out] out_handle  Output, handle which should be used for spi_flash_munmap call
  *
- * @return  ESP_OK on success, ESP_ERR_NO_MEM if pages can not be allocated
+ * @return
+ *      - ESP_OK on success
+ *      - ESP_ERR_NO_MEM if pages can not be allocated
+ *      - ESP_ERR_INVALID_ARG if pagecount is zero or pages array is not in
+ *        internal memory
  */
-esp_err_t spi_flash_mmap_pages(int *pages, size_t pagecount, spi_flash_mmap_memory_t memory,
+esp_err_t spi_flash_mmap_pages(const int *pages, size_t page_count, spi_flash_mmap_memory_t memory,
                          const void** out_ptr, spi_flash_mmap_handle_t* out_handle);
 
 
index 7f63d4c343242b7198df21c8734312403f382ded..045c140de54e7d4729e489b156229b2e55dd8fc8 100644 (file)
@@ -24,7 +24,9 @@
 #include "esp_partition.h"
 #include "esp_flash_encrypt.h"
 #include "esp_log.h"
+#include "bootloader_common.h"
 
+#define HASH_LEN 32 /* SHA-256 digest length */
 
 #ifndef NDEBUG
 // Enable built-in checks in queue.h in debug builds
@@ -322,3 +324,23 @@ esp_err_t esp_partition_mmap(const esp_partition_t* partition, uint32_t offset,
     }
     return rc;
 }
+
+esp_err_t esp_partition_get_sha256(const esp_partition_t *partition, uint8_t *sha_256)
+{
+    return bootloader_common_get_sha256_of_partition(partition->address, partition->size, partition->type, sha_256);
+}
+
+bool esp_partition_check_identity(const esp_partition_t *partition_1, const esp_partition_t *partition_2)
+{
+    uint8_t sha_256[2][HASH_LEN] = { 0 };
+
+    if (esp_partition_get_sha256(partition_1, sha_256[0]) == ESP_OK &&
+        esp_partition_get_sha256(partition_2, sha_256[1]) == ESP_OK) {
+
+        if (memcmp(sha_256[0], sha_256[1], HASH_LEN) == 0) {
+            // The partitions are identity
+            return true;
+        }
+    }
+    return false;
+}
index 4ce825caef45d625b80eb041540538c63d23e7ba..c3d004ae396c65426f56cd40f2ee0a935457d4f0 100644 (file)
@@ -2,7 +2,9 @@ SOURCE_FILES := \
        app_update/esp_ota_eps.c \
        log/log.c \
        newlib/lock.c \
-       esp32/crc.cpp
+       esp32/crc.cpp \
+       esp32/esp_random.c \
+       bootloader_support/src/bootloader_common.c 
 
 INCLUDE_DIRS := \
        ../include \
diff --git a/components/spi_flash/sim/stubs/bootloader_support/include/bootloader_common.h b/components/spi_flash/sim/stubs/bootloader_support/include/bootloader_common.h
new file mode 100644 (file)
index 0000000..856eecd
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+#include <stdint.h>
+#include <stdio.h>
+#include "esp_err.h"
+
+esp_err_t bootloader_common_get_sha256_of_partition(uint32_t address, uint32_t size, int type, uint8_t *out_sha_256);
diff --git a/components/spi_flash/sim/stubs/bootloader_support/src/bootloader_common.c b/components/spi_flash/sim/stubs/bootloader_support/src/bootloader_common.c
new file mode 100644 (file)
index 0000000..c940fb4
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "esp_err.h"
+
+esp_err_t bootloader_common_get_sha256_of_partition (uint32_t address, uint32_t size, int type, uint8_t *out_sha_256)
+{
+    return ESP_OK;
+}
diff --git a/components/spi_flash/sim/stubs/esp32/esp_random.c b/components/spi_flash/sim/stubs/esp32/esp_random.c
new file mode 100644 (file)
index 0000000..389796d
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <stddef.h>
+
+#include "esp_system.h"
+
+uint32_t esp_random(void)
+{
+    return (uint32_t)rand();
+}
+
diff --git a/components/spi_flash/sim/stubs/esp32/include/esp_system.h b/components/spi_flash/sim/stubs/esp32/include/esp_system.h
new file mode 100644 (file)
index 0000000..74511d5
--- /dev/null
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint32_t esp_random(void);
+
+#ifdef __cplusplus
+}
+#endif
+
index 6c9bb6f759f3cbdc7925c85899c308cddd3c83e0..68cd216bcea6362df4331eae7742aabff527a3e3 100644 (file)
@@ -44,11 +44,13 @@ void esp_log_write(esp_log_level_t level, const char* tag, const char* format, .
 
 #define ESP_LOGE( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR)   { esp_log_write(ESP_LOG_ERROR,   tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
 
-#define ESP_LOGV( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
+#define ESP_LOGW( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN)    { esp_log_write(ESP_LOG_WARN,    tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
+
+#define ESP_LOGI( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO)    { esp_log_write(ESP_LOG_INFO,    tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
 
 #define ESP_LOGD( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG)   { esp_log_write(ESP_LOG_DEBUG,   tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
 
-#define ESP_LOGW( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN)    { esp_log_write(ESP_LOG_WARN,    tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
+#define ESP_LOGV( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
 
 // Assume that flash encryption is not enabled. Put here since in partition.c
 // esp_log.h is included later than esp_flash_encrypt.h.
index 70e5b0205ba60befc7acb858e9453fb67eb9fb83..e051af078953966d881d3cab6da185914b15feb6 100644 (file)
@@ -81,7 +81,7 @@ build: $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_HEADER) \
 $(ULP_EXP_DEP_OBJECTS) : $(ULP_EXPORTS_HEADER) $(ULP_SYM)
 
 # Finally, set all the variables processed by the build system. 
-COMPONENT_EXTRA_CLEAN := $(ULP_OBJECTS) \
+COMPONENT_EXTRA_CLEAN += $(ULP_OBJECTS) \
                        $(ULP_LD_SCRIPT) \
                        $(ULP_PREPROCESSED) \
                        $(ULP_ELF) $(ULP_BIN) \
@@ -91,6 +91,6 @@ COMPONENT_EXTRA_CLEAN := $(ULP_OBJECTS) \
                        $(ULP_DEP) \
                        $(ULP_LISTINGS)
 
-COMPONENT_EMBED_FILES := $(COMPONENT_BUILD_DIR)/$(ULP_BIN)
-COMPONENT_ADD_LDFLAGS := -l$(COMPONENT_NAME) -T $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_LD)
-COMPONENT_EXTRA_INCLUDES := $(COMPONENT_BUILD_DIR)
+COMPONENT_EMBED_FILES += $(COMPONENT_BUILD_DIR)/$(ULP_BIN)
+COMPONENT_ADD_LDFLAGS += -l$(COMPONENT_NAME) -T $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_LD)
+COMPONENT_EXTRA_INCLUDES += $(COMPONENT_BUILD_DIR)
index 64bfff8c4591304f163b2ffeae537c1b43c7b42d..8acbd7120b024bf09dea4e68d012a5fc5d3df670 100644 (file)
@@ -17,6 +17,7 @@
 #include <stddef.h>
 #include <stdlib.h>
 #include "esp_err.h"
+#include "soc/soc.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -860,7 +861,7 @@ esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* prog
  * 3. TEXT_SIZE, size of .text section (2 bytes)
  * 4. DATA_SIZE, size of .data section (2 bytes)
  * 5. BSS_SIZE, size of .bss section (2 bytes)
- * 6. (TEXT_OFFSET - 16) bytes of arbitrary data (will not be loaded into RTC memory)
+ * 6. (TEXT_OFFSET - 12) bytes of arbitrary data (will not be loaded into RTC memory)
  * 7. .text section
  * 8. .data section
  *
index ce464a212a6ae8526bdd5fc5178740b99f524935..41228b2576963216d814875831081f980c883ac7 100644 (file)
@@ -1 +1,11 @@
-COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
+ULP_APP_NAME = ulp_test
+
+ULP_S_SOURCES = $(addprefix $(COMPONENT_PATH)/ulp/, \
+       test_jumps.S \
+       )
+
+ULP_EXP_DEP_OBJECTS := test_ulp_as.o
+include $(IDF_PATH)/components/ulp/component_ulp_common.mk
+
+COMPONENT_ADD_LDFLAGS += -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
diff --git a/components/ulp/test/test_ulp_as.c b/components/ulp/test/test_ulp_as.c
new file mode 100644 (file)
index 0000000..b0a0807
--- /dev/null
@@ -0,0 +1,25 @@
+#include <unistd.h>
+#include "unity.h"
+#include "soc/rtc_cntl_reg.h"
+#include "esp32/ulp.h"
+#include "ulp_test.h"
+
+
+extern const uint8_t ulp_test_bin_start[] asm("_binary_ulp_test_bin_start");
+extern const uint8_t ulp_test_bin_end[]   asm("_binary_ulp_test_bin_end");
+
+
+TEST_CASE("jumps condition", "[ulp]")
+{
+    esp_err_t err = ulp_load_binary(0, ulp_test_bin_start,
+            (ulp_test_bin_end - ulp_test_bin_start) / sizeof(uint32_t));
+    TEST_ESP_OK(err);
+
+    REG_CLR_BIT(RTC_CNTL_INT_RAW_REG, RTC_CNTL_ULP_CP_INT_RAW);
+    TEST_ESP_OK(ulp_run(&ulp_test_jumps - RTC_SLOW_MEM));
+    usleep(10000);
+
+    TEST_ASSERT_NOT_EQUAL(0, REG_GET_BIT(RTC_CNTL_INT_RAW_REG, RTC_CNTL_ULP_CP_INT_RAW));
+    TEST_ASSERT_EQUAL(0, ulp_jumps_fail & UINT16_MAX);
+    TEST_ASSERT_EQUAL(1, ulp_jumps_pass & UINT16_MAX);
+}
diff --git a/components/ulp/test/ulp/test_jumps.S b/components/ulp/test/ulp/test_jumps.S
new file mode 100644 (file)
index 0000000..65df226
--- /dev/null
@@ -0,0 +1,101 @@
+#include "soc/rtc_cntl_reg.h"
+#include "soc/rtc_io_reg.h"
+#include "soc/soc_ulp.h"
+
+       .bss
+
+       .global jumps_pass
+jumps_pass:
+       .long 0
+
+       .global jumps_fail
+jumps_fail:
+       .long 0
+
+       .text
+       .global test_jumps
+test_jumps:
+
+       /* tests for LT (less than) condition */
+       stage_rst           /* cnt = 0 */
+       jumps test_fail, 0, LT /* 0 < 0: false, should not jump */
+       jumps 1f, 1, LT     /* 0 < 1: true, should jump */
+       jump test_fail
+1:
+       stage_inc 2         /* cnt = 2 */
+       jumps 1f, 3, LT     /* 2 < 1: true */
+       jump test_fail
+1:
+       jumps test_fail, 1, LT  /* 2 < 1: false */
+       jumps test_fail, 2, LT  /* 2 < 2: false */
+
+       /* tests for LE (less or equal) condition */
+       stage_rst           /* cnt = 0 */
+       jumps 1f, 0, LE     /* 0 <= 0: true */
+       jump test_fail
+1:
+       jumps 1f, 1, LE     /* 0 <= 1: true */
+       jump test_fail
+1:
+       stage_inc 2         /* cnt = 2 */
+       jumps test_fail, 1, LE  /* 2 <= 1: false */
+
+       /* tests for EQ (equal) condition */
+       stage_rst           /* cnt = 0 */
+       jumps 1f, 0, EQ     /* 0 = 0: true */
+       jump test_fail
+1:
+       jumps test_fail, 1, EQ  /* 0 = 1: false */
+
+       stage_inc 1         /* cnt = 1 */
+       jumps test_fail, 0, EQ  /* 1 = 0: false */
+       jumps test_fail, 2, EQ  /* 1 = 2: false */
+       jumps 1f, 1, EQ         /* 1 = 1: true */
+1:
+
+       /* tests for GE (greater or equal) condition */
+       stage_rst           /* cnt = 0 */
+       jumps 1f, 0, GE     /* 0 >= 0: true */
+       jump test_fail
+1:
+       jumps test_fail, 1, GE  /* 0 >= 1: false */
+
+       stage_inc 1         /* cnt = 1 */
+       jumps 1f, 0, GE     /* 1 >= 0: true */
+       jump test_fail
+1:
+       jumps 1f, 1, GE     /* 1 >= 1: true */
+       jump test_fail
+1:
+       jumps test_fail, 2, GE  /* 1 >= 2: false */
+
+       /* tests for GT (greater than) condition */
+       stage_rst           /* cnt = 0 */
+       jumps test_fail, 0, GT  /* 0 > 0: false */
+       jumps test_fail, 1, GE  /* 0 > 1: false */
+
+       stage_inc 1         /* cnt = 1 */
+       jumps 1f, 0, GT     /* 1 > 0: true */
+       jump test_fail
+1:
+       jumps test_fail, 1, GT  /* 1 > 1: false */
+       jumps test_fail, 2, GT  /* 1 > 2: false */
+
+       jump test_pass
+
+test_fail:
+       move r0, jumps_fail
+       move r1, 1
+       st r1, r0, 0
+       jump done
+
+test_pass:
+       move r0, jumps_pass
+       move r1, 1
+       st r1, r0, 0
+       jump done
+
+       .global done
+done:
+       wake
+       halt
index 030acd22cc8d9a4277069a274e7ed24bec05ae80..06d3da5ef7e5e4deceeb49065b3ac82d6190d994 100644 (file)
 // limitations under the License.
 
 #include <stdio.h>
+#include "esp_system.h"
 #include "esp_log.h"
 #include "WL_Flash.h"
 #include <stdlib.h>
 #include "crc32.h"
 #include <string.h>
+#include <stddef.h>
 
 static const char *TAG = "wl_flash";
 #ifndef WL_CFG_CRC_CONST
@@ -55,9 +57,12 @@ esp_err_t WL_Flash::config(wl_config_t *cfg, Flash_Access *flash_drv)
              cfg->version,
              (uint32_t) cfg->temp_buff_size);
 
-    cfg->crc = crc32::crc32_le(WL_CFG_CRC_CONST, (const unsigned char *)cfg, sizeof(wl_config_t) - sizeof(cfg->crc));
+    cfg->crc = crc32::crc32_le(WL_CFG_CRC_CONST, (const unsigned char *)cfg, offsetof(wl_config_t, crc));
     esp_err_t result = ESP_OK;
     memcpy(&this->cfg, cfg, sizeof(wl_config_t));
+    if (this->cfg.temp_buff_size < this->cfg.wr_size) {
+        this->cfg.temp_buff_size = this->cfg.wr_size;
+    }
     this->configured = false;
     if (cfg == NULL) {
         result = ESP_ERR_INVALID_ARG;
@@ -74,7 +79,6 @@ esp_err_t WL_Flash::config(wl_config_t *cfg, Flash_Access *flash_drv)
     }
     WL_RESULT_CHECK(result);
 
-    this->temp_buff = (uint8_t *)malloc(this->cfg.temp_buff_size);
     this->state_size = this->cfg.sector_size;
     if (this->state_size < (sizeof(wl_state_t) + (this->cfg.full_mem_size / this->cfg.sector_size)*this->cfg.wr_size)) {
         this->state_size = ((sizeof(wl_state_t) + (this->cfg.full_mem_size / this->cfg.sector_size) * this->cfg.wr_size) + this->cfg.sector_size - 1) / this->cfg.sector_size;
@@ -87,11 +91,27 @@ esp_err_t WL_Flash::config(wl_config_t *cfg, Flash_Access *flash_drv)
     this->addr_state1 = this->cfg.start_addr + this->cfg.full_mem_size - this->state_size * 2 - this->cfg_size; // allocate data at the end of memory
     this->addr_state2 = this->cfg.start_addr + this->cfg.full_mem_size - this->state_size * 1 - this->cfg_size; // allocate data at the end of memory
 
+    ptrdiff_t flash_sz = ((this->cfg.full_mem_size - this->state_size * 2 - this->cfg_size) / this->cfg.page_size - 1) * this->cfg.page_size; // -1 remove dummy block
     this->flash_size = ((this->cfg.full_mem_size - this->state_size * 2 - this->cfg_size) / this->cfg.page_size - 1) * this->cfg.page_size; // -1 remove dummy block
 
-    ESP_LOGV(TAG, "%s - this->addr_state1=0x%08x", __func__, (uint32_t) this->addr_state1);
-    ESP_LOGV(TAG, "%s - this->addr_state2=0x%08x", __func__, (uint32_t) this->addr_state2);
+    ESP_LOGD(TAG, "%s - config result: state_size=0x%08x, cfg_size=0x%08x, addr_cfg=0x%08x, addr_state1=0x%08x, addr_state2=0x%08x, flash_size=0x%08x", __func__,
+             (uint32_t) this->state_size,
+             (uint32_t) this->cfg_size,
+             (uint32_t) this->addr_cfg,
+             (uint32_t) this->addr_state1,
+             (uint32_t) this->addr_state2,
+             (uint32_t) this->flash_size
+            );
+    if (flash_sz <= 0) {
+        result = ESP_ERR_INVALID_ARG;
+    }
+    WL_RESULT_CHECK(result);
 
+    this->temp_buff = (uint8_t *)malloc(this->cfg.temp_buff_size);
+    if (this->temp_buff == NULL) {
+        result = ESP_ERR_NO_MEM;
+    }
+    WL_RESULT_CHECK(result);
     this->configured = true;
     return ESP_OK;
 }
@@ -112,12 +132,12 @@ esp_err_t WL_Flash::init()
     result = this->flash_drv->read(this->addr_state2, state_copy, sizeof(wl_state_t));
     WL_RESULT_CHECK(result);
 
-    int check_size = sizeof(wl_state_t) - sizeof(uint32_t);
+    int check_size = offsetof(wl_state_t, crc);
     // Chech CRC and recover state
     uint32_t crc1 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, check_size);
     uint32_t crc2 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)state_copy, check_size);
 
-    ESP_LOGD(TAG, "%s - config ID=%i, stored ID=%i, access_count=%i, block_size=%i, max_count=%i, pos=%i, move_count=%i",
+    ESP_LOGD(TAG, "%s - config ID=%i, stored ID=%i, access_count=%i, block_size=%i, max_count=%i, pos=%i, move_count=0x%8.8X",
              __func__,
              this->cfg.version,
              this->state.version,
@@ -127,8 +147,7 @@ esp_err_t WL_Flash::init()
              this->state.pos,
              this->state.move_count);
 
-
-    ESP_LOGD(TAG, "%s starts: crc1=%i, crc2 = %i, this->state.crc=%i, state_copy->crc=%i", __func__, crc1, crc2, this->state.crc, state_copy->crc);
+    ESP_LOGD(TAG, "%s starts: crc1= 0x%08x, crc2 = 0x%08x, this->state.crc= 0x%08x, state_copy->crc= 0x%08x, version=%i, read_version=%i", __func__, crc1, crc2, this->state.crc, state_copy->crc, this->cfg.version, this->state.version);
     if ((crc1 == this->state.crc) && (crc2 == state_copy->crc)) {
         // The state is OK. Check the ID
         if (this->state.version != this->cfg.version) {
@@ -143,22 +162,30 @@ esp_err_t WL_Flash::init()
                 result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t));
                 WL_RESULT_CHECK(result);
                 for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size)*this->cfg.wr_size); i++) {
-                    uint8_t pos_bits = 0;
-                    result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i, &pos_bits, 1);
+                    bool pos_bits;
+                    result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
                     WL_RESULT_CHECK(result);
-                    if (pos_bits != 0xff) {
-                        result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i, &pos_bits, 1);
+                    pos_bits = this->OkBuffSet(i);
+                    if (pos_bits == true) {
+                        //this->fillOkBuff(i);
+                        result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
                         WL_RESULT_CHECK(result);
                     }
                 }
             }
-            ESP_LOGD(TAG, "%s: crc1=%i, crc2 = %i, result=%i", __func__, crc1, crc2, result);
+            ESP_LOGD(TAG, "%s: crc1=0x%08x, crc2 = 0x%08x, result= 0x%08x", __func__, crc1, crc2, (uint32_t)result);
             result = this->recoverPos();
             WL_RESULT_CHECK(result);
         }
-    } else if ((crc1 != this->state.crc) && (crc2 != state_copy->crc)) { // This is just new flash
-        result = this->initSections();
-        WL_RESULT_CHECK(result);
+    } else if ((crc1 != this->state.crc) && (crc2 != state_copy->crc)) { // This is just new flash or new version
+        // Check if this is new version or just new instance of WL
+        ESP_LOGD(TAG, "%s: try to update version - crc1= 0x%08x, crc2 = 0x%08x, result= 0x%08x", __func__, (uint32_t)crc1, (uint32_t)crc2, (uint32_t)result);
+        result = this->updateVersion();
+        if (result == ESP_FAIL) {
+            ESP_LOGD(TAG, "%s: init flash sections", __func__);
+            result = this->initSections();
+            WL_RESULT_CHECK(result);
+        }
         result = this->recoverPos();
         WL_RESULT_CHECK(result);
     } else {
@@ -169,11 +196,12 @@ esp_err_t WL_Flash::init()
             result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t));
             WL_RESULT_CHECK(result);
             for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size) * this->cfg.wr_size); i++) {
-                uint8_t pos_bits = 0;
-                result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i, &pos_bits, 1);
+                bool pos_bits;
+                result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
                 WL_RESULT_CHECK(result);
-                if (pos_bits != 0xff) {
-                    result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i, &pos_bits, 1);
+                pos_bits = this->OkBuffSet(i);
+                if (pos_bits == true) {
+                    result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
                     WL_RESULT_CHECK(result);
                 }
             }
@@ -185,11 +213,13 @@ esp_err_t WL_Flash::init()
             result = this->flash_drv->write(this->addr_state1, state_copy, sizeof(wl_state_t));
             WL_RESULT_CHECK(result);
             for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size) * this->cfg.wr_size); i++) {
-                uint8_t pos_bits = 0;
-                result = this->flash_drv->read(this->addr_state2 + sizeof(wl_state_t) + i, &pos_bits, 1);
+                bool pos_bits;
+                result = this->flash_drv->read(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
+
                 WL_RESULT_CHECK(result);
-                if (pos_bits != 0xff) {
-                    result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i, &pos_bits, 1);
+                pos_bits = this->OkBuffSet(i);
+                if (pos_bits == true) {
+                    result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
                     WL_RESULT_CHECK(result);
                 }
             }
@@ -206,10 +236,11 @@ esp_err_t WL_Flash::init()
     }
     if (result != ESP_OK) {
         this->initialized = false;
-        ESP_LOGE(TAG, "%s: returned 0x%x", __func__, result);
+        ESP_LOGE(TAG, "%s: returned 0x%08x", __func__, (uint32_t)result);
         return result;
     }
     this->initialized = true;
+    ESP_LOGD(TAG, "%s - move_count= 0x%08x", __func__, (uint32_t)this->state.move_count);
     return ESP_OK;
 }
 
@@ -217,20 +248,25 @@ esp_err_t WL_Flash::recoverPos()
 {
     esp_err_t result = ESP_OK;
     size_t position = 0;
+    ESP_LOGV(TAG, "%s start", __func__);
     for (size_t i = 0; i < this->state.max_pos; i++) {
-        uint8_t pos_bits = 0;
-        result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, &pos_bits, 1);
-        WL_RESULT_CHECK(result);
+        bool pos_bits;
         position = i;
-        if (pos_bits == 0xff) {
+        result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
+        pos_bits = this->OkBuffSet(i);
+        WL_RESULT_CHECK(result);
+        ESP_LOGV(TAG, "%s - check pos: result=0x%08x, position= %i, pos_bits= 0x%08x", __func__, (uint32_t)result, (uint32_t)position, (uint32_t)pos_bits);
+        if (pos_bits == false) {
             break; // we have found position
         }
     }
+
     this->state.pos = position;
     if (this->state.pos == this->state.max_pos) {
         this->state.pos--;
     }
-    ESP_LOGD(TAG, "%s - this->state.pos=0x%08x, result=%08x", __func__, this->state.pos, result);
+    ESP_LOGD(TAG, "%s - this->state.pos= 0x%08x, position= 0x%08x, result= 0x%08x, max_pos= 0x%08x", __func__, (uint32_t)this->state.pos, (uint32_t)position, (uint32_t)result, (uint32_t)this->state.max_pos);
+    ESP_LOGV(TAG, "%s done", __func__);
     return result;
 }
 
@@ -247,11 +283,12 @@ esp_err_t WL_Flash::initSections()
     }
     this->state.version = this->cfg.version;
     this->state.block_size = this->cfg.page_size;
-    this->used_bits = 0;
+    this->state.device_id = esp_random();
+    memset(this->state.reserved, 0, sizeof(this->state.reserved));
 
     this->state.max_pos = 1 + this->flash_size / this->cfg.page_size;
 
-    this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, sizeof(wl_state_t) - sizeof(uint32_t));
+    this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, offsetof(wl_state_t, crc));
 
     result = this->flash_drv->erase_range(this->addr_state1, this->state_size);
     WL_RESULT_CHECK(result);
@@ -268,11 +305,126 @@ esp_err_t WL_Flash::initSections()
     result = this->flash_drv->write(this->addr_cfg, &this->cfg, sizeof(wl_config_t));
     WL_RESULT_CHECK(result);
 
-    ESP_LOGD(TAG, "%s - this->state->max_count=%08x, this->state->max_pos=%08x", __func__, this->state.max_count, this->state.max_pos);
-    ESP_LOGD(TAG, "%s - result=%08x", __func__, result);
+    ESP_LOGD(TAG, "%s - this->state->max_count= 0x%08x, this->state->max_pos= 0x%08x", __func__, this->state.max_count, this->state.max_pos);
+    ESP_LOGD(TAG, "%s - result= 0x%08x", __func__, result);
+    return result;
+}
+
+esp_err_t WL_Flash::updateVersion()
+{
+    esp_err_t result = ESP_OK;
+
+    result = this->updateV1_V2();
+    if (result == ESP_OK) {
+        return result;
+    }
+    // check next version
     return result;
 }
 
+esp_err_t WL_Flash::updateV1_V2()
+{
+    esp_err_t result = ESP_OK;
+    // Check crc for old version and old version
+    ESP_LOGV(TAG, "%s start", __func__);
+    int check_size = offsetof(wl_state_t, device_id);
+    // Chech CRC and recover state
+    uint32_t crc1 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, check_size);
+    wl_state_t sa_copy;
+    wl_state_t *state_copy = &sa_copy;
+    result = this->flash_drv->read(this->addr_state2, state_copy, sizeof(wl_state_t));
+    WL_RESULT_CHECK(result);
+    uint32_t crc2 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)state_copy, check_size);
+
+    // For V1 crc in place of device_id and version
+    uint32_t v1_crc1 = this->state.device_id;
+    uint32_t v1_crc2 = state_copy->device_id;
+
+    ESP_LOGD(TAG, "%s - process crc1=0x%08x, crc2=0x%08x, v1_crc1=0x%08x, v1_crc2=0x%08x, version=%i", __func__, crc1, crc2, v1_crc1, v1_crc2, this->state.version);
+
+    if ((crc1 == v1_crc1) && (crc2 == v1_crc2) && (v1_crc1 == v1_crc2) && (this->state.version == 1) && (state_copy->version == 1)) {
+        // Here we have to update all internal structures
+        ESP_LOGI(TAG, "%s Update from V1 to V2, crc=0x%08x, ", __func__, crc1);
+        uint32_t pos = 0;
+
+        for (size_t i = 0; i < this->state.max_pos; i++) {
+            uint8_t pos_bits;
+            result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, &pos_bits, 1);
+            WL_RESULT_CHECK(result);
+            ESP_LOGV(TAG, "%s- result= 0x%08x, pos= %i, pos_bits= 0x%08x", __func__, (uint32_t)result, (uint32_t)pos, (uint32_t)pos_bits);
+            pos = i;
+            if (pos_bits == 0xff) {
+                break; // we have found position
+            }
+        }
+        ESP_LOGI(TAG, "%s max_pos=%i, pos=%i, state.ver=%i, state2.ver=%i", __func__, (uint32_t)this->state.max_pos, (uint32_t)pos, (uint32_t)this->state.version, (uint32_t)state_copy->version);
+        if (pos == this->state.max_pos) {
+            pos--;
+        }
+        WL_RESULT_CHECK(result);
+
+        this->state.version = 2;
+        this->state.pos = 0;
+        this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, offsetof(wl_state_t, crc));
+        this->state.device_id = esp_random();
+        memset(this->state.reserved, 0, sizeof(this->state.reserved));
+
+        result = this->flash_drv->erase_range(this->addr_state1, this->state_size);
+        WL_RESULT_CHECK(result);
+        result = this->flash_drv->write(this->addr_state1, &this->state, sizeof(wl_state_t));
+        WL_RESULT_CHECK(result);
+
+        memset(this->temp_buff, 0, this->cfg.wr_size);
+        for (uint32_t i = 0 ; i <= pos; i++) {
+            this->fillOkBuff(i);
+            result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
+            WL_RESULT_CHECK(result);
+        }
+
+        result = this->flash_drv->erase_range(this->addr_state2, this->state_size);
+        WL_RESULT_CHECK(result);
+        result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t));
+        WL_RESULT_CHECK(result);
+        ESP_LOGD(TAG, "%s - move_count= 0x%08x, pos= 0x%08x", __func__, this->state.move_count, this->state.pos);
+
+        memset(this->temp_buff, 0, this->cfg.wr_size);
+        for (uint32_t i = 0 ; i <= pos; i++) {
+            this->fillOkBuff(i);
+            result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
+            WL_RESULT_CHECK(result);
+        }
+        this->state.pos = pos;
+        return result;
+    }
+
+    return ESP_FAIL;
+}
+
+void WL_Flash::fillOkBuff(int n)
+{
+    uint32_t *buff = (uint32_t *)this->temp_buff;
+
+    for (int i = 0 ; i < 4 ; i++) {
+        buff[i] = this->state.device_id + n * 4 + i;
+        buff[i] = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&buff[i], sizeof(uint32_t));
+    }
+}
+
+bool WL_Flash::OkBuffSet(int n)
+{
+    bool result = true;
+    uint32_t *data_buff = (uint32_t *)this->temp_buff;
+    for (int i = 0 ; i < 4 ; i++) {
+        uint32_t data = this->state.device_id + n * 4 + i;
+        uint32_t crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&data, sizeof(uint32_t));
+        if (crc != data_buff[i]) {
+            result = false;
+        }
+    }
+    return result;
+}
+
+
 esp_err_t WL_Flash::updateWL()
 {
     esp_err_t result = ESP_OK;
@@ -282,7 +434,7 @@ esp_err_t WL_Flash::updateWL()
     }
     // Here we have to move the block and increase the state
     this->state.access_count = 0;
-    ESP_LOGV(TAG, "%s - access_count=0x%08x, pos=0x%08x", __func__, this->state.access_count, this->state.pos);
+    ESP_LOGV(TAG, "%s - access_count= 0x%08x, pos= 0x%08x", __func__, this->state.access_count, this->state.pos);
     // copy data to dummy block
     size_t data_addr = this->state.pos + 1; // next block, [pos+1] copy to [pos]
     if (data_addr >= this->state.max_pos) {
@@ -292,7 +444,7 @@ esp_err_t WL_Flash::updateWL()
     this->dummy_addr = this->cfg.start_addr + this->state.pos * this->cfg.page_size;
     result = this->flash_drv->erase_range(this->dummy_addr, this->cfg.page_size);
     if (result != ESP_OK) {
-        ESP_LOGE(TAG, "%s - erase wl dummy sector result=%08x", __func__, result);
+        ESP_LOGE(TAG, "%s - erase wl dummy sector result= 0x%08x", __func__, result);
         this->state.access_count = this->state.max_count - 1; // we will update next time
         return result;
     }
@@ -301,13 +453,13 @@ esp_err_t WL_Flash::updateWL()
     for (size_t i = 0; i < copy_count; i++) {
         result = this->flash_drv->read(data_addr + i * this->cfg.temp_buff_size, this->temp_buff, this->cfg.temp_buff_size);
         if (result != ESP_OK) {
-            ESP_LOGE(TAG, "%s - not possible to read buffer, will try next time, result=%08x", __func__, result);
+            ESP_LOGE(TAG, "%s - not possible to read buffer, will try next time, result= 0x%08x", __func__, result);
             this->state.access_count = this->state.max_count - 1; // we will update next time
             return result;
         }
         result = this->flash_drv->write(this->dummy_addr + i * this->cfg.temp_buff_size, this->temp_buff, this->cfg.temp_buff_size);
         if (result != ESP_OK) {
-            ESP_LOGE(TAG, "%s - not possible to write buffer, will try next time, result=%08x", __func__, result);
+            ESP_LOGE(TAG, "%s - not possible to write buffer, will try next time, result= 0x%08x", __func__, result);
             this->state.access_count = this->state.max_count - 1; // we will update next time
             return result;
         }
@@ -316,17 +468,18 @@ esp_err_t WL_Flash::updateWL()
     // Here we will update structures...
     // Update bits and save to flash:
     uint32_t byte_pos = this->state.pos * this->cfg.wr_size;
-    this->used_bits = 0;
+    this->fillOkBuff(this->state.pos);
     // write state to mem. We updating only affected bits
-    result |= this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + byte_pos, &this->used_bits, this->cfg.wr_size);
+    result |= this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + byte_pos, this->temp_buff, this->cfg.wr_size);
     if (result != ESP_OK) {
-        ESP_LOGE(TAG, "%s - update position 1 result=%08x", __func__, result);
+        ESP_LOGE(TAG, "%s - update position 1 result= 0x%08x", __func__, result);
         this->state.access_count = this->state.max_count - 1; // we will update next time
         return result;
     }
-    result |= this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + byte_pos, &this->used_bits, this->cfg.wr_size);
+    this->fillOkBuff(this->state.pos);
+    result |= this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + byte_pos, this->temp_buff, this->cfg.wr_size);
     if (result != ESP_OK) {
-        ESP_LOGE(TAG, "%s - update position 2 result=%08x", __func__, result);
+        ESP_LOGE(TAG, "%s - update position 2 result= 0x%08x", __func__, result);
         this->state.access_count = this->state.max_count - 1; // we will update next time
         return result;
     }
@@ -340,7 +493,7 @@ esp_err_t WL_Flash::updateWL()
             this->state.move_count = 0;
         }
         // write main state
-        this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, sizeof(wl_state_t) - sizeof(uint32_t));
+        this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, offsetof(wl_state_t, crc));
 
         result = this->flash_drv->erase_range(this->addr_state1, this->state_size);
         WL_RESULT_CHECK(result);
@@ -350,13 +503,13 @@ esp_err_t WL_Flash::updateWL()
         WL_RESULT_CHECK(result);
         result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t));
         WL_RESULT_CHECK(result);
-        ESP_LOGD(TAG, "%s - move_count=%08x", __func__, this->state.move_count);
+        ESP_LOGD(TAG, "%s - move_count= 0x%08x, pos= 0x%08x, ", __func__, this->state.move_count, this->state.pos);
     }
     // Save structures to the flash... and check result
     if (result == ESP_OK) {
-        ESP_LOGV(TAG, "%s - result=%08x", __func__, result);
+        ESP_LOGV(TAG, "%s - result= 0x%08x", __func__, result);
     } else {
-        ESP_LOGE(TAG, "%s - result=%08x", __func__, result);
+        ESP_LOGE(TAG, "%s - result= 0x%08x", __func__, result);
     }
     return result;
 }
@@ -369,7 +522,7 @@ size_t WL_Flash::calcAddr(size_t addr)
     } else {
         result += this->cfg.page_size;
     }
-    ESP_LOGV(TAG, "%s - addr=0x%08x -> result=0x%08x", __func__, (uint32_t) addr, (uint32_t) result);
+    ESP_LOGV(TAG, "%s - addr= 0x%08x -> result= 0x%08x, dummy_addr= 0x%08x", __func__, (uint32_t) addr, (uint32_t) result, (uint32_t)dummy_addr);
     return result;
 }
 
@@ -396,7 +549,7 @@ esp_err_t WL_Flash::erase_sector(size_t sector)
     if (!this->initialized) {
         return ESP_ERR_INVALID_STATE;
     }
-    ESP_LOGV(TAG, "%s - sector=0x%08x", __func__, (uint32_t) sector);
+    ESP_LOGD(TAG, "%s - sector= 0x%08x", __func__, (uint32_t) sector);
     result = this->updateWL();
     WL_RESULT_CHECK(result);
     size_t virt_addr = this->calcAddr(sector * this->cfg.sector_size);
@@ -410,14 +563,14 @@ esp_err_t WL_Flash::erase_range(size_t start_address, size_t size)
     if (!this->initialized) {
         return ESP_ERR_INVALID_STATE;
     }
-    ESP_LOGV(TAG, "%s - start_address=0x%08x, size=0x%08x", __func__, (uint32_t) start_address, (uint32_t) size);
+    ESP_LOGD(TAG, "%s - start_address= 0x%08x, size= 0x%08x", __func__, (uint32_t) start_address, (uint32_t) size);
     size_t erase_count = (size + this->cfg.sector_size - 1) / this->cfg.sector_size;
     size_t start_sector = start_address / this->cfg.sector_size;
     for (size_t i = 0; i < erase_count; i++) {
         result = this->erase_sector(start_sector + i);
         WL_RESULT_CHECK(result);
     }
-    ESP_LOGV(TAG, "%s - result=%08x", __func__, result);
+    ESP_LOGV(TAG, "%s - result= 0x%08x", __func__, result);
     return result;
 }
 
@@ -427,7 +580,7 @@ esp_err_t WL_Flash::write(size_t dest_addr, const void *src, size_t size)
     if (!this->initialized) {
         return ESP_ERR_INVALID_STATE;
     }
-    ESP_LOGV(TAG, "%s - dest_addr=0x%08x, size=0x%08x", __func__, (uint32_t) dest_addr, (uint32_t) size);
+    ESP_LOGD(TAG, "%s - dest_addr= 0x%08x, size= 0x%08x", __func__, (uint32_t) dest_addr, (uint32_t) size);
     uint32_t count = (size - 1) / this->cfg.page_size;
     for (size_t i = 0; i < count; i++) {
         size_t virt_addr = this->calcAddr(dest_addr + i * this->cfg.page_size);
@@ -446,10 +599,11 @@ esp_err_t WL_Flash::read(size_t src_addr, void *dest, size_t size)
     if (!this->initialized) {
         return ESP_ERR_INVALID_STATE;
     }
-    ESP_LOGV(TAG, "%s - src_addr=0x%08x, size=0x%08x", __func__, (uint32_t) src_addr, (uint32_t) size);
+    ESP_LOGD(TAG, "%s - src_addr= 0x%08x, size= 0x%08x", __func__, (uint32_t) src_addr, (uint32_t) size);
     uint32_t count = (size - 1) / this->cfg.page_size;
     for (size_t i = 0; i < count; i++) {
         size_t virt_addr = this->calcAddr(src_addr + i * this->cfg.page_size);
+        ESP_LOGV(TAG, "%s - real_addr= 0x%08x, size= 0x%08x", __func__, (uint32_t) (this->cfg.start_addr + virt_addr), (uint32_t) size);
         result = this->flash_drv->read(this->cfg.start_addr + virt_addr, &((uint8_t *)dest)[i * this->cfg.page_size], this->cfg.page_size);
         WL_RESULT_CHECK(result);
     }
@@ -473,6 +627,6 @@ esp_err_t WL_Flash::flush()
     esp_err_t result = ESP_OK;
     this->state.access_count = this->state.max_count - 1;
     result = this->updateWL();
-    ESP_LOGV(TAG, "%s - result=%08x", __func__, result);
+    ESP_LOGD(TAG, "%s - result= 0x%08x, move_count= 0x%08x", __func__, result, this->state.move_count);
     return result;
 }
index d09b86b62e1046504eeb8cd46bbeb7e51760766c..9492140d26ebcdc09508a0fd22fd177ac2f0212f 100644 (file)
@@ -5,6 +5,11 @@ Wear Levelling Component (WLC) it is a software component that is implemented to
 The WLC do not have internal cache. When write operation is finished, that means that data was really stored to the flash.
 As a parameter the WLC requires the driver to access the flash device. The driver has to implement Flash_Access interface.
 
+The WLC Versioning and Compatibility
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The WLC accept data formats from older version. Latest version of the WLC will update data format from older versions to the current one. 
+Current implementation of WLC has version 2. The data format from current version incompatible with data format from previous versions, and could not be 
+used with previous versions.
 
 The WLC Files
 ^^^^^^^^^^^^^^^
@@ -49,9 +54,9 @@ The wl_config_t contains configuration parameters for the WLC component.
 Internal Memory Organization
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 The WLC divide the memory that are define by start_addr and full_mem_size to three regions:
- - Configuration
  - Data
  - States
+ - Configuration
  
 The Configuration region used to store configuration information. The user can use it to recover the WLC from memory dump.
 The Data - is a region where user data stored. 
index 182320cafdf91a761456a28c222bfe8a34a186d1..19a682e064ddd039a10b8bed3a79c9c1e6532a19 100644 (file)
@@ -65,12 +65,17 @@ protected:
     uint32_t cfg_size;
     uint8_t *temp_buff = NULL;
     size_t dummy_addr;
-    uint8_t used_bits;
+    uint32_t pos_data[4];
 
     esp_err_t initSections();
     esp_err_t updateWL();
     esp_err_t recoverPos();
     size_t calcAddr(size_t addr);
+
+    esp_err_t updateVersion();
+    esp_err_t updateV1_V2();
+    void fillOkBuff(int n);
+    bool OkBuffSet(int n);
 };
 
 #endif // _WL_Flash_H_
index 39a76ba5eac63b72315e4e74901196349eb70f15..7464ba9b8b123e090e4fb5b8901538f816a85e9c 100644 (file)
 * @brief This structure is used to store current state of flash access
 *
 */
-typedef struct WL_State_s {
+#if defined(_MSC_VER)
+#define ALIGNED_(x) __declspec(align(x))
+#else
+#if defined(__GNUC__)
+#define ALIGNED_(x) __attribute__ ((aligned(x)))
+#endif
+#endif
+
+typedef struct ALIGNED_(32) WL_State_s {
 public:
     uint32_t pos;           /*!< current dummy block position*/
     uint32_t max_pos;       /*!< maximum amount of positions*/
@@ -28,7 +36,14 @@ public:
     uint32_t max_count;     /*!< max access count when block will be moved*/
     uint32_t block_size;    /*!< size of move block*/
     uint32_t version;       /*!< state id used to identify the version of current libary implementaion*/
+    uint32_t device_id;     /*!< ID of current WL instance*/
+    uint32_t reserved[7];   /*!< Reserved space for future use*/
     uint32_t crc;           /*!< CRC of structure*/
 } wl_state_t;
 
+#ifndef _MSC_VER // MSVS has different format for this define
+static_assert(sizeof(wl_state_t) % 16 == 0, "Size of wl_state_t structure should be compatible with flash encryption");
+#endif // _MSC_VER
+
+
 #endif // _WL_State_H_
index ce464a212a6ae8526bdd5fc5178740b99f524935..47bab9648544e82866188d847abee17f5aa95e34 100644 (file)
@@ -1 +1,2 @@
 COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
+COMPONENT_EMBED_FILES := test_partition_v1.bin
diff --git a/components/wear_levelling/test/test_partition_v1.bin b/components/wear_levelling/test/test_partition_v1.bin
new file mode 100644 (file)
index 0000000..c4b2437
Binary files /dev/null and b/components/wear_levelling/test/test_partition_v1.bin differ
index 8aa3e6f4396fdea3932b8fff52ee559ee9913df3..02dba8f78e6e9d3aaa41eaac20c009cdcce02598 100644 (file)
@@ -6,6 +6,8 @@
 #include "freertos/portable.h"
 #include "freertos/task.h"
 #include "freertos/semphr.h"
+#include "esp_clk.h"
+#include "soc/cpu.h"
 
 TEST_CASE("wl_unmount doesn't leak memory", "[wear_levelling]")
 {
@@ -17,7 +19,13 @@ TEST_CASE("wl_unmount doesn't leak memory", "[wear_levelling]")
     TEST_ESP_OK(wl_mount(partition, &handle));
     wl_unmount(handle);
     size_t size_after = xPortGetFreeHeapSize();
-    TEST_ASSERT_EQUAL_UINT32(size_before, size_after);
+
+    // Original code:
+    //TEST_ASSERT_EQUAL_HEX32(size_before, size_after);
+    // Workaround for problem with heap size calculation:
+    ptrdiff_t stack_diff = size_before - size_after; 
+    stack_diff = abs(stack_diff);
+    if (stack_diff > 8) TEST_ASSERT_EQUAL(0, stack_diff);
 }
 
 TEST_CASE("wl_mount check partition parameters", "[wear_levelling][ignore]")
@@ -27,22 +35,39 @@ TEST_CASE("wl_mount check partition parameters", "[wear_levelling][ignore]")
     memcpy(&fake_partition, test_partition, sizeof(fake_partition));
     wl_handle_t handle;
     size_t size_before, size_after;
+    wl_unmount(WL_INVALID_HANDLE);
 
-    // test small partition
-    fake_partition.size = SPI_FLASH_SEC_SIZE;
-    size_before = xPortGetFreeHeapSize();
-    TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle));
-    size_after = xPortGetFreeHeapSize();
-    TEST_ASSERT_EQUAL_HEX32(size_before, size_after);
-    // currently this test leaks memory
+    esp_partition_erase_range(test_partition, 0, test_partition->size);
+    // test small partition: result should be error
+    for (int i=0 ; i< 5 ; i++)
+    {
+        fake_partition.size = SPI_FLASH_SEC_SIZE*(i);
+        size_before = xPortGetFreeHeapSize();
+        TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle));
+        size_after = xPortGetFreeHeapSize();
 
-    // test slightly bigger partition
-    fake_partition.size = SPI_FLASH_SEC_SIZE * 3;
+        // Original code:
+        //TEST_ASSERT_EQUAL_HEX32(size_before, size_after);
+        // Workaround for problem with heap size calculation:
+        ptrdiff_t stack_diff = size_before - size_after; 
+        stack_diff = abs(stack_diff);
+        if (stack_diff > 8) TEST_ASSERT_EQUAL(0, stack_diff);
+    }
+
+    // test minimum size partition: result should be OK
+    fake_partition.size = SPI_FLASH_SEC_SIZE * 5;
     size_before = xPortGetFreeHeapSize();
-    TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle));
+    TEST_ESP_OK(wl_mount(&fake_partition, &handle));
+    wl_unmount(handle);
+    printf("Test done\n");
     size_after = xPortGetFreeHeapSize();
-    TEST_ASSERT_EQUAL_HEX32(size_before, size_after);
-    // currently this test hangs
+
+    // Original code:
+    //TEST_ASSERT_EQUAL_HEX32(size_before, size_after);
+    // Workaround for problem with heap size calculation:
+    ptrdiff_t stack_diff = size_before - size_after; 
+    stack_diff = abs(stack_diff);
+    if (stack_diff > 8) TEST_ASSERT_EQUAL(0, stack_diff);
 }
 
 typedef struct {
@@ -151,3 +176,130 @@ TEST_CASE("multiple tasks can access wl handle simultaneously", "[wear_levelling
     vSemaphoreDelete(args4.done);
     wl_unmount(handle);
 }
+
+#define TEST_SECTORS_COUNT 8
+
+static void check_mem_data(wl_handle_t handle, uint32_t init_val, uint32_t* buff)
+{
+    size_t sector_size = wl_sector_size(handle);
+
+    for (int m=0 ; m < TEST_SECTORS_COUNT ; m++) {
+        TEST_ESP_OK(wl_read(handle, sector_size * m, buff, sector_size));
+        for (int i=0 ; i< sector_size/sizeof(uint32_t) ; i++) {
+            uint32_t compare_val = init_val + i +  m*sector_size;
+            TEST_ASSERT_EQUAL( buff[i], compare_val);
+        }
+    }
+}
+
+
+// We write complete memory with defined data
+// And then write one sector many times.
+// A data in other secors should be the same.
+// We do this also with unmount
+TEST_CASE("multiple write is correct", "[wear_levelling]")
+{
+    const esp_partition_t *partition = get_test_data_partition();
+    esp_partition_t fake_partition;
+    memcpy(&fake_partition, partition, sizeof(fake_partition));
+
+    fake_partition.size = SPI_FLASH_SEC_SIZE*(4 + TEST_SECTORS_COUNT);
+
+    wl_handle_t handle;
+    TEST_ESP_OK(wl_mount(&fake_partition, &handle));
+
+    size_t sector_size = wl_sector_size(handle);
+    // Erase 8 sectors
+    TEST_ESP_OK(wl_erase_range(handle, 0, sector_size * TEST_SECTORS_COUNT));
+    // Write data to all sectors
+    printf("Check 1 sector_size=0x%08x\n", sector_size);
+    // Set initial random value
+    uint32_t init_val = rand();
+    
+    uint32_t* buff = (uint32_t*)malloc(sector_size);
+    for (int m=0 ; m < TEST_SECTORS_COUNT ; m++) {
+        for (int i=0 ; i< sector_size/sizeof(uint32_t) ; i++) {
+            buff[i] = init_val + i +  m*sector_size;
+        }
+        TEST_ESP_OK(wl_erase_range(handle, sector_size*m, sector_size));
+        TEST_ESP_OK(wl_write(handle, sector_size*m, buff, sector_size));
+    }
+
+    check_mem_data(handle, init_val, buff);
+    
+    uint32_t start;
+    RSR(CCOUNT, start);
+
+
+    for (int m=0 ; m< 100000 ; m++) {
+        uint32_t sector = m % TEST_SECTORS_COUNT;
+        for (int i=0 ; i< sector_size/sizeof(uint32_t) ; i++) {
+            buff[i] = init_val + i +  sector*sector_size;
+        }
+        TEST_ESP_OK(wl_erase_range(handle, sector_size*sector, sector_size));
+        TEST_ESP_OK(wl_write(handle, sector_size*sector, buff, sector_size));
+        check_mem_data(handle, init_val, buff);
+
+        uint32_t end;
+        RSR(CCOUNT, end);
+        uint32_t ms = (end - start) / (esp_clk_cpu_freq() / 1000);
+        printf("loop %4i pass, time= %ims\n", m, ms);
+        if (ms > 10000) {
+            break;
+        }
+    }
+
+    free(buff);
+    wl_unmount(handle);
+}
+
+extern const uint8_t test_partition_v1_bin_start[] asm("_binary_test_partition_v1_bin_start");
+extern const uint8_t test_partition_v1_bin_end[]   asm("_binary_test_partition_v1_bin_end");
+
+#define COMPARE_START_CONST 0x12340000
+
+// We write to partition prepared image with V1
+// Then we convert image to new version and verifying the data 
+
+TEST_CASE("Version update test", "[wear_levelling]")
+{
+    const esp_partition_t *partition = get_test_data_partition();
+    esp_partition_t fake_partition;
+    memcpy(&fake_partition, partition, sizeof(fake_partition));
+
+    if (partition->encrypted)
+    {
+        printf("Update from V1 to V2 will not work.\n");    
+        return;
+    }
+    fake_partition.size = (size_t)(test_partition_v1_bin_end - test_partition_v1_bin_start);
+
+    printf("Data file size = %i, partition address = 0x%08x, file addr=0x%08x\n", (uint32_t)fake_partition.size, (uint32_t)fake_partition.address, (uint32_t)test_partition_v1_bin_start);
+
+    esp_partition_erase_range(&fake_partition, 0, fake_partition.size);
+
+    esp_partition_write(&fake_partition, 0, test_partition_v1_bin_start,  fake_partition.size);
+
+    wl_handle_t handle;
+    TEST_ESP_OK(wl_mount(&fake_partition, &handle));
+    size_t sector_size = wl_sector_size(handle);
+    uint32_t* buff = (uint32_t*)malloc(sector_size);
+
+    uint32_t init_val = COMPARE_START_CONST;
+    int test_count = fake_partition.size/sector_size - 4;
+
+    for (int m=0 ; m <  test_count; m++) {
+        TEST_ESP_OK(wl_read(handle, sector_size * m, buff, sector_size));
+        for (int i=0 ; i< sector_size/sizeof(uint32_t) ; i++) {
+            uint32_t compare_val = init_val + i +  m*sector_size;
+            if (buff[i] != compare_val)
+            {
+                printf("error compare: 0x%08x != 0x%08x \n", buff[i], compare_val);
+            }
+            TEST_ASSERT_EQUAL( buff[i], compare_val);
+        }
+    }
+
+    free(buff);
+    wl_unmount(handle);
+}
index eaf5e7b3b72a17220dfca0d4fede4f35fd5bbe0e..5d94990cc26c43819738ee2b55d0db92f248a8a8 100644 (file)
@@ -16,6 +16,7 @@ SPI_FLASH_SIM_LIB := libspi_flash.a
 include Makefile.files
 
 all: test
+       
 
 ifndef SDKCONFIG
 SDKCONFIG_DIR := $(dir $(realpath sdkconfig/sdkconfig.h))
index 798fb629da4d0c166cb01402146f13ef7220d85d..e5e5ffeb8086c4341530d2255e8a639b364d35b2 100644 (file)
@@ -45,7 +45,7 @@
 #endif //WL_DEFAULT_START_ADDR
 
 #ifndef WL_CURRENT_VERSION
-#define WL_CURRENT_VERSION  1
+#define WL_CURRENT_VERSION  2
 #endif //WL_CURRENT_VERSION
 
 typedef struct {
@@ -174,7 +174,6 @@ esp_err_t wl_unmount(wl_handle_t handle)
     _lock_acquire(&s_instances_lock);
     result = check_handle(handle, __func__);
     if (result == ESP_OK) {
-        ESP_LOGV(TAG, "deleting handle 0x%08x", handle);
         // We have to flush state of the component
         result = s_instances[handle].instance->flush();
         // We use placement new in wl_mount, so call destructor directly
index d2120dbc3996f8c987acef5521aad561c81da7b6..ae73ccf12634be46dd9a6ea2bc2bcab81de09bbb 100644 (file)
@@ -1,4 +1,4 @@
-COMPONENT_ADD_INCLUDEDIRS := include port/include ../esp32/include
+COMPONENT_ADD_INCLUDEDIRS := include port/include
 COMPONENT_SRCDIRS := src/crypto port src/fast_crypto src/wpa2/eap_peer src/wpa2/tls src/wpa2/utils src/wps
 
 CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -D__ets__ -Wno-strict-aliasing
index 5c86893b88338b50006b98794980eb351a4f0e46..d91b7cf23a0cc9c65642c45aad0977d36eea3145 100644 (file)
@@ -144,6 +144,8 @@ INPUT = \
     ../../components/esp32/include/esp_ipc.h \
     ## Over The Air Updates (OTA)
     ../../components/app_update/include/esp_ota_ops.h \
+    ## ESP HTTPS OTA
+    ../../components/esp_https_ota/include/esp_https_ota.h \
     ## Sleep
     ## NOTE: for line below header_file.inc is not used
     ../../components/esp32/include/esp_sleep.h \
diff --git a/docs/_static/espressif-logo.svg b/docs/_static/espressif-logo.svg
new file mode 100644 (file)
index 0000000..210ae20
--- /dev/null
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->\r
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+        viewBox="0 0 787.5 190.5" style="enable-background:new 0 0 787.5 190.5;" xml:space="preserve">\r
+<style type="text/css">\r
+       .st0{display:none;fill:none;stroke:#D5D5D5;stroke-width:0.8701;}\r
+       .st1{clip-path:url(#SVGID_2_);}\r
+       .st2{fill:#FF3034;}\r
+       .st3{clip-path:url(#SVGID_4_);}\r
+       .st4{clip-path:url(#SVGID_5_);fill:#FF3034;}\r
+       .st5{clip-path:url(#SVGID_6_);}\r
+       .st6{clip-path:url(#SVGID_8_);}\r
+</style>\r
+<line class="st0" x1="458.7" y1="111.1" x2="458.6" y2="179.4"/>\r
+<g>\r
+       <defs>\r
+               <rect id="SVGID_1_" x="-3.6" y="205.4" width="197" height="328"/>\r
+       </defs>\r
+       <clipPath id="SVGID_2_">\r
+               <use xlink:href="#SVGID_1_"  style="overflow:visible;"/>\r
+       </clipPath>\r
+       <g class="st1">\r
+               <rect x="1.4" y="211.4" class="st2" width="186" height="186"/>\r
+               <text transform="matrix(1 0 0 1 -0.6101 430.4418)"><tspan x="0" y="0" style="font-family:'HelveticaNeue-Bold'; font-size:21.0508px;">ESPRESSIF  LOGO</tspan><tspan x="0" y="24" style="font-family:'HelveticaNeue-Bold'; font-size:20px;">Pantone No. 3556 C</tspan><tspan x="0" y="48" style="font-family:'HelveticaNeue-Medium'; font-size:15px;">CMYK   0/83/96/0</tspan><tspan x="0" y="66" style="font-family:'HelveticaNeue-Medium'; font-size:15px;">RGB     255/48/52</tspan><tspan x="0" y="84" style="font-family:'HelveticaNeue-Medium'; font-size:15px;"># FF3034</tspan></text>\r
+       </g>\r
+</g>\r
+<g>\r
+       <defs>\r
+               <rect id="SVGID_3_" x="-3.6" y="-4.6" width="794" height="198"/>\r
+       </defs>\r
+       <clipPath id="SVGID_4_">\r
+               <use xlink:href="#SVGID_3_"  style="overflow:visible;"/>\r
+       </clipPath>\r
+       <g class="st3">\r
+               <defs>\r
+                       <rect id="SVGID_7_" x="67.2" y="37.7" width="117" height="117.6"/>\r
+               </defs>\r
+               <clipPath id="SVGID_5_">\r
+                       <use xlink:href="#SVGID_7_"  style="overflow:visible;"/>\r
+               </clipPath>\r
+               <path class="st4" d="M105.9,125.2c0,4.6-3.7,8.3-8.3,8.3c-4.6,0-8.3-3.7-8.3-8.3c0-4.6,3.7-8.3,8.3-8.3\r
+                       C102.2,116.9,105.9,120.6,105.9,125.2"/>\r
+               <path class="st4" d="M178.1,116.6C172.8,79,143,49.2,105.4,43.9c-4.4,2.3-8.4,5.3-12,8.7v8c37.5,0,68,30.5,68,68h8\r
+                       C172.8,125,175.7,121,178.1,116.6"/>\r
+               <path class="st4" d="M184.3,91.5c0-29.7-24.1-53.8-53.8-53.8c-1.9,0-3.7,0.1-5.5,0.3l-1.2,3.5c26.4,9.2,47.4,30.2,56.6,56.6\r
+                       l3.6-1.3C184.2,95.1,184.3,93.3,184.3,91.5"/>\r
+               <path class="st4" d="M130.4,132.2c1.3-13.3-4.6-25.8-14.6-33.3c-5.3-4-11.7-6.6-18.7-7.3c-1.8-0.2-3.2-1.8-3-3.6\r
+                       c0.2-1.7,1.6-3,3.2-3c0.1,0,0.3,0,0.4,0c7.6,0.8,14.6,3.4,20.5,7.5c12.7,8.8,20.4,24,18.7,40.4c-0.3,2.6-0.8,5.1-1.5,7.5l9.7,2.7\r
+                       c2.9-0.8,5.7-1.9,8.4-3.2c0.7-3.7,1.1-7.5,1.1-11.5c0-30.7-22.7-56.3-52.3-60.6c-3.5-0.5-7.1-0.5-9.8,0.1\r
+                       c-9.1,2.3-15.8,10.5-15.8,20.3c0,9.3,6.1,17.3,14.6,19.9c1.6,0.5,4.1,0.7,5.3,0.9h0.1c9.2,1.6,16.3,9.7,16.3,19.4\r
+                       c0,3.9-1.2,7.5-3.1,10.6l6.7,4.3c3.2,0.9,6.6,1.4,10,1.7C128.7,141.1,130,136.8,130.4,132.2"/>\r
+               <path class="st4" d="M131.1,155.3c-17.1,0-33.1-6.6-45.2-18.7c-12.1-12.1-18.7-28.1-18.7-45.2c0-17.1,6.6-33.1,18.7-45.2\r
+                       c0.9-0.9,2.5-0.9,3.4,0c0.9,0.9,0.9,2.5,0,3.4c-11.2,11.2-17.3,26-17.3,41.8c0,15.8,6.1,30.6,17.3,41.8\r
+                       c11.2,11.2,26,17.3,41.8,17.3c15.8,0,30.6-6.1,41.8-17.3c0.9-0.9,2.5-0.9,3.4,0c0.9,0.9,0.9,2.5,0,3.4\r
+                       C164.2,148.7,148.2,155.3,131.1,155.3"/>\r
+       </g>\r
+       <g class="st3">\r
+               <defs>\r
+                       <rect id="SVGID_9_" x="231.3" y="61.5" width="477.5" height="70.1"/>\r
+               </defs>\r
+               <clipPath id="SVGID_6_">\r
+                       <use xlink:href="#SVGID_9_"  style="overflow:visible;"/>\r
+               </clipPath>\r
+               <polygon class="st5" points="231.3,62.3 231.3,130.7 278,130.7 278,118.3 245.4,118.3 245.4,74.6 276.6,74.6 276.6,62.3            "/>\r
+       </g>\r
+       <g class="st3">\r
+               <defs>\r
+                       <rect id="SVGID_11_" x="231.3" y="61.5" width="477.5" height="70.1"/>\r
+               </defs>\r
+               <clipPath id="SVGID_8_">\r
+                       <use xlink:href="#SVGID_11_"  style="overflow:visible;"/>\r
+               </clipPath>\r
+               <path class="st6" d="M311.3,131.6c-3.3,0-6.3-0.4-9-1.1c-2.7-0.7-5.1-1.7-7.2-3c-2.1-1.3-4-2.8-5.6-4.5c-1.6-1.8-2.9-3.6-3.9-5.6\r
+                       l11.5-6.6c1.5,2.5,3.4,4.5,5.5,6.1c2.1,1.6,4.9,2.4,8.4,2.4c2.9,0,5.3-0.7,7-2c1.7-1.3,2.6-3,2.6-5c0-2.4-0.9-4.2-2.7-5.4\r
+                       c-1.8-1.2-4.3-2.5-7.5-3.9l-3.5-1.5c-2.6-1.1-4.9-2.2-6.9-3.5c-2.1-1.3-3.9-2.8-5.3-4.4c-1.5-1.7-2.6-3.6-3.4-5.7\r
+                       c-0.8-2.1-1.2-4.7-1.2-7.6c0-2.6,0.5-5.1,1.5-7.4c1-2.3,2.3-4.3,4.1-5.9c1.8-1.7,3.9-3,6.5-3.9c2.5-0.9,5.4-1.4,8.5-1.4\r
+                       c4.5,0,8.4,0.9,11.6,2.6c3.3,1.7,6.1,4.6,8.4,8.8l-11,7c-1.2-2.1-2.5-3.7-3.9-4.6c-1.4-0.9-3.1-1.4-5.1-1.4\r
+                       c-2.1,0-3.7,0.6-4.9,1.7c-1.2,1.1-1.8,2.6-1.8,4.3c0,2.1,0.7,3.8,2.1,4.9c1.4,1.1,3.6,2.3,6.6,3.7l3.5,1.5c3,1.3,5.7,2.6,8,4\r
+                       c2.3,1.4,4.3,2.9,5.8,4.6c1.6,1.7,2.8,3.6,3.6,5.8c0.8,2.2,1.3,4.7,1.3,7.7c0,3.1-0.6,5.9-1.8,8.4c-1.2,2.4-2.8,4.5-4.9,6.2\r
+                       c-2.1,1.7-4.5,2.9-7.4,3.8C317.7,131.1,314.6,131.6,311.3,131.6"/>\r
+               <path class="st6" d="M345.5,62.3h18.9c4.8,0,9,0.6,12.8,1.8c3.8,1.2,7,2.9,9.6,5.2c2.6,2.3,4.6,5.1,6,8.3c1.4,3.3,2.1,7,2.1,11.1\r
+                       c0,4.2-0.7,7.9-2.1,11.1c-1.4,3.2-3.4,6-6,8.2c-2.6,2.2-5.8,4-9.6,5.2c-3.8,1.2-8.1,1.8-12.8,1.8h-4.8v15.6h-14.1V62.3z\r
+                        M364,102.7c5.8,0,10-1.2,12.6-3.5c2.6-2.3,3.9-5.8,3.9-10.5c0-4.8-1.3-8.3-4-10.6c-2.7-2.3-6.8-3.5-12.5-3.5h-4.4v28.1H364z"/>\r
+               <path class="st6" d="M456.5,130.7h-16.3l-11.3-17.3c-1.3,0.2-2.7,0.3-4,0.3h-4.8v17H406V62.3h18.9c9.6,0,17.1,2.2,22.5,6.6\r
+                       c5.4,4.4,8.1,10.8,8.1,19.2c0,5.4-1.1,9.8-3.4,13.2c-2.3,3.4-5.5,6.1-9.8,8L456.5,130.7z M424.5,101.4c5.8,0,10-1,12.6-3\r
+                       c2.6-2,3.9-5.4,3.9-10.3c0-4.8-1.3-8.3-4-10.4c-2.7-2.1-6.8-3.1-12.5-3.1h-4.4v26.7H424.5z"/>\r
+               <path class="st6" d="M547.7,131.6c-3.3,0-6.3-0.4-9-1.1c-2.7-0.7-5.1-1.7-7.2-3c-2.1-1.3-4-2.8-5.6-4.5c-1.6-1.8-2.9-3.6-3.9-5.6\r
+                       l11.5-6.6c1.5,2.5,3.4,4.5,5.5,6.1c2.1,1.6,4.9,2.4,8.4,2.4c2.9,0,5.3-0.7,7-2c1.7-1.3,2.6-3,2.6-5c0-2.4-0.9-4.2-2.7-5.4\r
+                       c-1.8-1.2-4.3-2.5-7.5-3.9l-3.5-1.5c-2.5-1.1-4.9-2.2-6.9-3.5c-2.1-1.3-3.9-2.8-5.3-4.4c-1.5-1.7-2.6-3.6-3.4-5.7\r
+                       c-0.8-2.1-1.2-4.7-1.2-7.6c0-2.6,0.5-5.1,1.5-7.4c1-2.3,2.3-4.3,4.1-5.9c1.8-1.7,3.9-3,6.5-3.9c2.5-0.9,5.4-1.4,8.5-1.4\r
+                       c4.5,0,8.4,0.9,11.6,2.6c3.2,1.7,6,4.6,8.4,8.8l-11,7c-1.2-2.1-2.5-3.7-3.9-4.6c-1.4-0.9-3.1-1.4-5.1-1.4c-2.1,0-3.7,0.6-4.9,1.7\r
+                       c-1.2,1.1-1.8,2.6-1.8,4.3c0,2.1,0.7,3.8,2.1,4.9c1.4,1.1,3.6,2.3,6.6,3.7l3.5,1.5c3,1.3,5.7,2.6,8,4c2.3,1.4,4.3,2.9,5.8,4.6\r
+                       c1.6,1.7,2.8,3.6,3.6,5.8c0.8,2.2,1.3,4.7,1.3,7.7c0,3.1-0.6,5.9-1.8,8.4c-1.2,2.4-2.8,4.5-4.9,6.2c-2.1,1.7-4.5,2.9-7.4,3.8\r
+                       C554.1,131.1,551,131.6,547.7,131.6"/>\r
+               <path class="st6" d="M601.6,131.6c-3.3,0-6.3-0.4-8.9-1.1c-2.7-0.7-5.1-1.7-7.2-3c-2.1-1.3-4-2.8-5.6-4.5\r
+                       c-1.6-1.8-2.9-3.6-3.9-5.6l11.5-6.6c1.5,2.5,3.4,4.5,5.5,6.1c2.1,1.6,4.9,2.4,8.4,2.4c2.9,0,5.3-0.7,7-2c1.7-1.3,2.6-3,2.6-5\r
+                       c0-2.4-0.9-4.2-2.7-5.4c-1.8-1.2-4.3-2.5-7.5-3.9l-3.5-1.5c-2.5-1.1-4.9-2.2-6.9-3.5c-2.1-1.3-3.9-2.8-5.3-4.4\r
+                       c-1.5-1.7-2.6-3.6-3.4-5.7c-0.8-2.1-1.2-4.7-1.2-7.6c0-2.6,0.5-5.1,1.5-7.4c1-2.3,2.3-4.3,4.1-5.9c1.8-1.7,3.9-3,6.5-3.9\r
+                       c2.5-0.9,5.4-1.4,8.5-1.4c4.5,0,8.4,0.9,11.6,2.6c3.2,1.7,6,4.6,8.4,8.8l-11,7c-1.2-2.1-2.5-3.7-3.9-4.6c-1.4-0.9-3.1-1.4-5.1-1.4\r
+                       c-2.1,0-3.7,0.6-4.9,1.7c-1.2,1.1-1.8,2.6-1.8,4.3c0,2.1,0.7,3.8,2.1,4.9c1.4,1.1,3.6,2.3,6.6,3.7l3.5,1.5c3,1.3,5.7,2.6,8,4\r
+                       c2.3,1.4,4.3,2.9,5.8,4.6c1.6,1.7,2.8,3.6,3.6,5.8c0.8,2.2,1.3,4.7,1.3,7.7c0,3.1-0.6,5.9-1.8,8.4c-1.2,2.4-2.8,4.5-4.9,6.2\r
+                       c-2.1,1.7-4.5,2.9-7.4,3.8C608.1,131.1,605,131.6,601.6,131.6"/>\r
+               <rect x="636.2" y="62.3" class="st6" width="14.1" height="68.4"/>\r
+               <polygon class="st6" points="664.8,62.3 708.8,62.3 708.8,74.6 678.9,74.6 678.9,130.7 664.8,130.7                "/>\r
+               <polygon class="st6" points="467.7,62.3 513,62.3 513,74.6 481.8,74.6 481.8,118.3 514.4,118.3 514.4,130.7 467.7,130.7            "/>\r
+               <path class="st6" d="M678.9,119.3L665.2,130c0-19.6,12.6-39.4,40.9-39.4v12.7C686.8,103.3,678.9,113.5,678.9,119.3"/>\r
+               <path class="st6" d="M245.3,118.4l-14,11.6c0-19.6,12.6-39.4,40.9-39.4v12.7c-19.1,0-26.6,10.1-26.8,14.9\r
+                       C245.4,118.2,245.3,118.3,245.3,118.4"/>\r
+               <path class="st6" d="M481.7,118.4l-14,11.6c0-19.6,12.6-39.4,40.9-39.4v12.7c-19.1,0-26.6,10.1-26.8,14.9\r
+                       C481.8,118.2,481.7,118.3,481.7,118.4"/>\r
+       </g>\r
+</g>\r
+</svg>\r
index 63ee6cc74ce038abb92976e6821248e73378dce6..df1cdd4425277e500fe6f550894831864ba4d8e0 100644 (file)
@@ -1,13 +1,42 @@
 /* override table width restrictions */
 @media screen and (min-width: 767px) {
 
-   .wy-table-responsive table td {
-      /* !important prevents the common CSS stylesheets from overriding
-         this as on RTD they are loaded after this stylesheet */
-      white-space: normal !important;
-   }
-
-   .wy-table-responsive {
-      overflow: visible !important;
-   }
+  .wy-table-responsive table td {
+    /* !important prevents the common CSS stylesheets from overriding
+       this as on RTD they are loaded after this stylesheet */
+    white-space: normal !important;
+  }
+
+  .wy-table-responsive {
+    overflow: visible !important;
+  }
+}
+
+.wy-side-nav-search {
+  background-color: #e3e3e3 !important;
+}
+
+.wy-side-nav-search input[type=text] {
+   border-radius: 0px !important;
+   border-color: #333333 !important;
+}
+
+.icon-home {
+  color: #333333 !important;
+}
+
+.icon-home:hover {
+  background-color: #d6d6d6 !important;
+}
+
+.version {
+  color: #000000 !important;
+}
+
+a:hover {
+  color: #bd2c2a !important;
+}
+
+.logo {
+  width: 240px !important;
 }
index 47465323500ef2cdeb7e3243ba5ebccb3a9bf7d6..244810a9fbe68177bd807a7433035f750c2e4b6c 100644 (file)
@@ -56,6 +56,17 @@ if os.system('python ../../tools/gen_esp_err_to_name.py --rst_output ' + esp_err
     raise RuntimeError('gen_esp_err_to_name.py failed')
 copy_if_modified(esp_err_inc_path + '.in', esp_err_inc_path)
 
+# Generate version-related includes
+#
+# (Note: this is in a function as it needs to access configuration to get the language)
+def generate_version_specific_includes(app):
+    print("Generating version-specific includes...")
+    version_tmpdir = '{}/version_inc'.format(builddir)
+    if os.system('python ../gen-version-specific-includes.py {} {}'.format(app.config.language, version_tmpdir)):
+        raise RuntimeError('gen-version-specific-includes.py failed')
+    copy_if_modified(version_tmpdir, '{}/inc'.format(builddir))
+
+
 # http://stackoverflow.com/questions/12772927/specifying-an-online-image-in-sphinx-restructuredtext-format
 # 
 suppress_warnings = ['image.nonlocal_uri']
@@ -167,7 +178,7 @@ pygments_style = 'sphinx'
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
-html_theme = 'default'
+html_theme = 'sphinx_rtd_theme'
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
@@ -186,7 +197,7 @@ html_theme = 'default'
 
 # The name of an image file (relative to this directory) to place at the top
 # of the sidebar.
-#html_logo = None
+html_logo = "../_static/espressif-logo.svg"
 
 # The name of an image file (within the static path) to use as favicon of the
 # docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
@@ -326,20 +337,8 @@ texinfo_documents = [
 # If true, do not generate a @detailmenu in the "Top" node's menu.
 #texinfo_no_detailmenu = False
 
-# -- Use sphinx_rtd_theme for local builds --------------------------------
-# ref. https://github.com/snide/sphinx_rtd_theme#using-this-theme-locally-then-building-on-read-the-docs
-#
-# on_rtd is whether we are on readthedocs.org
-on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
-
-if not on_rtd:  # only import and set the theme if we're building docs locally
-    import sphinx_rtd_theme
-    html_theme = 'sphinx_rtd_theme'
-    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
-
-# otherwise, readthedocs.org uses their theme by default, so no need to specify it
-
 # Override RTD CSS theme to introduce the theme corrections
 # https://github.com/rtfd/sphinx_rtd_theme/pull/432
 def setup(app):
     app.add_stylesheet('theme_overrides.css')
+    generate_version_specific_includes(app)
diff --git a/docs/docs_common.mk b/docs/docs_common.mk
new file mode 100644 (file)
index 0000000..85056dc
--- /dev/null
@@ -0,0 +1,213 @@
+# "Common" Makefile for Sphinx documentation
+#
+# (included from en/Makefile & zh_CN/Makefile
+#
+# NOTE: This makefile runs with cwd=either en or zh_CN subfolder, so this
+# (docs/) directory is '..' relative to it.
+
+# ************ IMPORTANT *****************
+#
+# ReadTheDocs DOES NOT USE THIS MAKEFILE,
+# so any behaviour additions must be
+# done via Sphinx Config not here
+#
+# ****************************************
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) -w sphinx-warning-log.txt .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext dependencies version-specific-includes
+
+help:
+       @echo "Please use \`make <target>\' where <target> is one of"
+       @echo "  html       to make standalone HTML files"
+       @echo "  dirhtml    to make HTML files named index.html in directories"
+       @echo "  singlehtml to make a single large HTML file"
+       @echo "  pickle     to make pickle files"
+       @echo "  json       to make JSON files"
+       @echo "  htmlhelp   to make HTML files and a HTML help project"
+       @echo "  qthelp     to make HTML files and a qthelp project"
+       @echo "  devhelp    to make HTML files and a Devhelp project"
+       @echo "  epub       to make an epub"
+       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+       @echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+       @echo "  text       to make text files"
+       @echo "  man        to make manual pages"
+       @echo "  texinfo    to make Texinfo files"
+       @echo "  info       to make Texinfo files and run them through makeinfo"
+       @echo "  gettext    to make PO message catalogs"
+       @echo "  changes    to make an overview of all changed/added/deprecated items"
+       @echo "  xml        to make Docutils-native XML files"
+       @echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+       @echo "  linkcheck  to check all external links for integrity"
+       @echo "  doctest    to run all doctests embedded in the documentation (if enabled) "
+
+clean:
+       rm -rf $(BUILDDIR)/*
+
+html:
+       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+       @echo
+       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+       @echo
+       @echo "Build finished; now you can process the pickle files."
+
+json:
+       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+       @echo
+       @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+       @echo
+       @echo "Build finished; now you can run HTML Help Workshop with the" \
+             ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+       @echo
+       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhcp"
+       @echo "To view the help file:"
+       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhc"
+
+devhelp:
+       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+       @echo
+       @echo "Build finished."
+       @echo "To view the help file:"
+       @echo "# mkdir -p $$HOME/.local/share/devhelp/ReadtheDocsTemplate"
+       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ReadtheDocsTemplate"
+       @echo "# devhelp"
+
+epub:
+       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+       @echo
+       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo
+       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+       @echo "Run \`make' in that directory to run these through (pdf)latex" \
+             "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through pdflatex..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through platex and dvipdfmx..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+       @echo
+       @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+       @echo
+       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo
+       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+       @echo "Run \`make' in that directory to run these through makeinfo" \
+             "(use \`make info' here to do that automatically)."
+
+info:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo "Running Texinfo files through makeinfo..."
+       make -C $(BUILDDIR)/texinfo info
+       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+       @echo
+       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+       @echo
+       @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+       @echo
+       @echo "Link check complete; look for any errors in the above output " \
+             "or in $(BUILDDIR)/linkcheck/output.txt."
+
+gh-linkcheck:
+       @echo "Checking for hardcoded GitHub links"
+       @if (find ../ -name '*.rst' | xargs grep \
+               'https://github.com/espressif/esp-idf/tree\|https://github.com/espressif/esp-idf/blob\|https://github.com/espressif/esp-idf/raw'\
+               ); \
+       then \
+               echo "WARNINIG: Some .rst files contain hardcoded Github links."; \
+               echo "Please check above output and replace links with one of the following:"; \
+               echo "- :idf:\`dir\` - points to directory inside ESP-IDF"; \
+               echo "- :idf_file:\`file\` - points to file inside ESP-IDF"; \
+               echo "- :idf_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
+               echo "- :component:\`dir\` - points to directory inside ESP-IDF components dir"; \
+               echo "- :component_file:\`file\` - points to file inside ESP-IDF components dir"; \
+               echo "- :component_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
+               echo "  components dir"; \
+               echo "- :example:\`dir\` - points to directory inside ESP-IDF examples dir"; \
+               echo "- :example_file:\`file\` - points to file inside ESP-IDF examples dir"; \
+               echo "- :example_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
+               echo "  examples dir"; \
+               echo "These link types will point to the correct GitHub version automatically"; \
+               exit 1; \
+       fi
+       @echo "No hardcoded links found"
+
+doctest:
+       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+       @echo "Testing of doctests in the sources finished, look at the " \
+             "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+       $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+       @echo
+       @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+       $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+       @echo
+       @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
index 5c3a71047254fece1f1b4eac46ad580ced14146a..2a6504abb07d6c6cda78299ee39e9bc704754a09 100644 (file)
@@ -35,7 +35,7 @@ These third party libraries can be included into the application (firmware) prod
 
 * `libcoap`_ COAP library Copyright (c) 2010-2017 Olaf Bergmann and others, is licensed under 2-clause BSD license.
 
-* `libexpat`_ XML parsing library Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper, Copyright (c) 2001-2016 Expat maintainers, is licensed under MIT license.
+* `libexpat`_ XML parsing library Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper, Copyright (c) 2001-2017 Expat maintainers, is licensed under MIT license.
 
 * `FatFS`_ library, Copyright (C) 2017 ChaN, is licensed under :component_file:`a BSD-style license <fatfs/src/ff.h#L1-L18>`.
 
index cc32abbd516fa5315b1619751f5b3a49ae5295d6..281b720196e417ddbeddffd3f4385010e97cea37 100644 (file)
@@ -1,201 +1,2 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS    =
-SPHINXBUILD   = sphinx-build
-PAPER         =
-BUILDDIR      = _build
-
-# User-friendly check for sphinx-build
-ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
-$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
-endif
-
-# Internal variables.
-PAPEROPT_a4     = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) -w sphinx-warning-log.txt .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
-help:
-       @echo "Please use \`make <target>' where <target> is one of"
-       @echo "  html       to make standalone HTML files"
-       @echo "  dirhtml    to make HTML files named index.html in directories"
-       @echo "  singlehtml to make a single large HTML file"
-       @echo "  pickle     to make pickle files"
-       @echo "  json       to make JSON files"
-       @echo "  htmlhelp   to make HTML files and a HTML help project"
-       @echo "  qthelp     to make HTML files and a qthelp project"
-       @echo "  devhelp    to make HTML files and a Devhelp project"
-       @echo "  epub       to make an epub"
-       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
-       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
-       @echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
-       @echo "  text       to make text files"
-       @echo "  man        to make manual pages"
-       @echo "  texinfo    to make Texinfo files"
-       @echo "  info       to make Texinfo files and run them through makeinfo"
-       @echo "  gettext    to make PO message catalogs"
-       @echo "  changes    to make an overview of all changed/added/deprecated items"
-       @echo "  xml        to make Docutils-native XML files"
-       @echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
-       @echo "  linkcheck  to check all external links for integrity"
-       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
-
-clean:
-       rm -rf $(BUILDDIR)/*
-
-html:
-       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
-       @echo
-       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
-       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
-       @echo
-       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
-       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
-       @echo
-       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
-       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
-       @echo
-       @echo "Build finished; now you can process the pickle files."
-
-json:
-       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
-       @echo
-       @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
-       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
-       @echo
-       @echo "Build finished; now you can run HTML Help Workshop with the" \
-             ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
-       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
-       @echo
-       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
-             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
-       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhcp"
-       @echo "To view the help file:"
-       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhc"
-
-devhelp:
-       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
-       @echo
-       @echo "Build finished."
-       @echo "To view the help file:"
-       @echo "# mkdir -p $$HOME/.local/share/devhelp/ReadtheDocsTemplate"
-       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ReadtheDocsTemplate"
-       @echo "# devhelp"
-
-epub:
-       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
-       @echo
-       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
-       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-       @echo
-       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
-       @echo "Run \`make' in that directory to run these through (pdf)latex" \
-             "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
-       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-       @echo "Running LaTeX files through pdflatex..."
-       $(MAKE) -C $(BUILDDIR)/latex all-pdf
-       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-latexpdfja:
-       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-       @echo "Running LaTeX files through platex and dvipdfmx..."
-       $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
-       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
-       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
-       @echo
-       @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
-       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
-       @echo
-       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
-       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-       @echo
-       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
-       @echo "Run \`make' in that directory to run these through makeinfo" \
-             "(use \`make info' here to do that automatically)."
-
-info:
-       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-       @echo "Running Texinfo files through makeinfo..."
-       make -C $(BUILDDIR)/texinfo info
-       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
-       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
-       @echo
-       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
-       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
-       @echo
-       @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
-       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
-       @echo
-       @echo "Link check complete; look for any errors in the above output " \
-             "or in $(BUILDDIR)/linkcheck/output.txt."
-
-gh-linkcheck:
-       @echo "Checking for hardcoded GitHub links"
-       @if (find ../ -name '*.rst' | xargs grep \
-               'https://github.com/espressif/esp-idf/tree\|https://github.com/espressif/esp-idf/blob\|https://github.com/espressif/esp-idf/raw'\
-               ); \
-       then \
-               echo "WARNINIG: Some .rst files contain hardcoded Github links."; \
-               echo "Please check above output and replace links with one of the following:"; \
-               echo "- :idf:\`dir\` - points to directory inside ESP-IDF"; \
-               echo "- :idf_file:\`file\` - points to file inside ESP-IDF"; \
-               echo "- :idf_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
-               echo "- :component:\`dir\` - points to directory inside ESP-IDF components dir"; \
-               echo "- :component_file:\`file\` - points to file inside ESP-IDF components dir"; \
-               echo "- :component_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
-               echo "  components dir"; \
-               echo "- :example:\`dir\` - points to directory inside ESP-IDF examples dir"; \
-               echo "- :example_file:\`file\` - points to file inside ESP-IDF examples dir"; \
-               echo "- :example_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
-               echo "  examples dir"; \
-               echo "These link types will point to the correct GitHub version automatically"; \
-               exit 1; \
-       fi
-       @echo "No hardcoded links found"
-
-doctest:
-       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
-       @echo "Testing of doctests in the sources finished, look at the " \
-             "results in $(BUILDDIR)/doctest/output.txt."
-
-xml:
-       $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
-       @echo
-       @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
-
-pseudoxml:
-       $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
-       @echo
-       @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
+LANGUAGE=en
+include ../docs_common.mk
index 84eec8297657998911baec493aeb064a74cbdb1f..db738943148f4599461b82725b110232302fe530 100644 (file)
@@ -65,6 +65,15 @@ Base64-encoded body of core dump will be between the following header and footer
 
 The `CORE DUMP START` and `CORE DUMP END` lines must not be included in core dump text file.
 
+ROM Functions in Backtraces
+---------------------------
+
+It is possible situation that at the moment of crash some tasks or/and crashed task itself have one or more ROM functions in their callstacks.
+Since ROM is not part of the program ELF it will be impossible for GDB to parse such callstacks, because it tries to analyse functions' prologues to acomplish that.
+In that case callstack printing will be broken with error message at the first ROM function.
+To overcome this issue you can use ROM ELF provided by Espressif (https://dl.espressif.com/dl/esp32_rom.elf) and pass it to 'espcoredump.py'.
+
+
 Running 'espcoredump.py'
 ------------------------------------
 
@@ -85,4 +94,5 @@ Generic command syntax:
     * --core-format,-t CORE_FORMAT. Specifies that file passed with "-c" is an ELF ("elf"), dumped raw binary ("raw") or base64-encoded ("b64") format.
     * --off,-o OFF.                 Ofsset of coredump partition in flash (type "make partition_table" to see it).
     * --save-core,-s SAVE_CORE.     Save core to file. Othwerwise temporary core file will be deleted. Ignored with "-c".
+    * --rom-elf,-r ROM_ELF.         Path to ROM ELF file to use (if skipped "esp32_rom.elf" is used).
     * --print-mem,-m                Print memory dump. Used only with "info_corefile".
index 14e5bc984b6cfa1fbb442f0e91b1400ab99d9dc4..eb397f389d7779b2c8c53d30e7b60f5daad4c9bb 100644 (file)
@@ -4,7 +4,7 @@ Partition Tables
 Overview
 --------
 
-A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x8000 in the flash.
+A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to (:envvar:`default offset <CONFIG_PARTITION_TABLE_OFFSET>`) 0x8000 in the flash.
 
 Partition table length is 0xC00 bytes (maximum 95 partition table entries). An MD5 checksum is appended after the table data. If the partition table is signed due to `secure boot`, the signature is appended after the partition table.
 
@@ -23,10 +23,10 @@ Built-in Partition Tables
 Here is the summary printed for the "Single factory app, no OTA" configuration::
 
   # Espressif ESP32 Partition Table
-  # Name,   Type, SubType, Offset,  Size
-  nvs,      data, nvs,     0x9000,  0x6000
-  phy_init, data, phy,     0xf000,  0x1000
-  factory,  app,  factory, 0x10000, 1M
+  # Name,   Type, SubType, Offset,  Size, Flags
+  nvs,      data, nvs,     0x9000,  0x6000,
+  phy_init, data, phy,     0xf000,  0x1000,
+  factory,  app,  factory, 0x10000, 1M,
 
 * At a 0x10000 (64KB) offset in the flash is the app labelled "factory". The bootloader will run this app by default.
 * There are also two data regions defined in the partition table for storing NVS library partition and PHY init data.
@@ -34,13 +34,13 @@ Here is the summary printed for the "Single factory app, no OTA" configuration::
 Here is the summary printed for the "Factory app, two OTA definitions" configuration::
 
   # Espressif ESP32 Partition Table
-  # Name,   Type, SubType, Offset,  Size
-  nvs,      data, nvs,     0x9000,  0x4000
-  otadata,  data, ota,     0xd000,  0x2000
-  phy_init, data, phy,     0xf000,  0x1000
-  factory,  0,    0,       0x10000, 1M
-  ota_0,    0,    ota_0,   ,        1M
-  ota_1,    0,    ota_1,   ,        1M
+  # Name,   Type, SubType, Offset,  Size, Flags
+  nvs,      data, nvs,     0x9000,  0x4000,
+  otadata,  data, ota,     0xd000,  0x2000,
+  phy_init, data, phy,     0xf000,  0x1000,
+  factory,  0,    0,       0x10000, 1M,
+  ota_0,    0,    ota_0,  0x110000, 1M,
+  ota_1,    0,    ota_1,  0x210000, 1M,
 
 * There are now three app partition definitions.
 * The type of all three are set as "app", but the subtype varies between the factory app at 0x10000 and the next two "OTA" apps.
@@ -53,17 +53,17 @@ If you choose "Custom partition table CSV" in menuconfig then you can also enter
 
 The CSV format is the same format as printed in the summaries shown above. However, not all fields are required in the CSV. For example, here is the "input" CSV for the OTA partition table::
 
-  # Name,   Type, SubType, Offset,   Size
-  nvs,      data, nvs,     0x9000,  0x4000
-  otadata,  data, ota,     0xd000,  0x2000
-  phy_init, data, phy,     0xf000,  0x1000
-  factory,  app,  factory, 0x10000,  1M
-  ota_0,    app,  ota_0,   ,         1M
-  ota_1,    app,  ota_1,   ,         1M
+  # Name,   Type, SubType, Offset, Size, Flags
+  nvs,      data, nvs,     ,       0x4000,
+  otadata,  data, ota,     ,       0x2000,
+  phy_init, data, phy,     ,       0x1000,
+  factory,  app,  factory, ,       1M,
+  ota_0,    app,  ota_0,   ,       1M,
+  ota_1,    app,  ota_1,   ,       1M,
 
 * Whitespace between fields is ignored, and so is any line starting with # (comments).
 * Each non-comment line in the CSV file is a partition definition.
-* Only the offset for the first partition is supplied. The gen_esp32part.py tool fills in each remaining offset to start after the preceding partition.
+* The "Offset" field for each partition is empty. The gen_esp32part.py tool fills in each blank offset, starting after the partition table and making sure each partition is aligned correctly.
 
 Name field
 ~~~~~~~~~~
@@ -121,12 +121,21 @@ Other data subtypes are reserved for future esp-idf uses.
 Offset & Size
 ~~~~~~~~~~~~~
 
-Only the first offset field is required (we recommend using 0x10000). Partitions with blank offsets will start after the previous partition.
+Partitions with blank offsets will start after the previous partition, or after the partition table in the case of the first partition.
 
 App partitions have to be at offsets aligned to 0x10000 (64K). If you leave the offset field blank, the tool will automatically align the partition. If you specify an unaligned offset for an app partition, the tool will return an error.
 
 Sizes and offsets can be specified as decimal numbers, hex numbers with the prefix 0x, or size multipliers K or M (1024 and 1024*1024 bytes).
 
+If you want the partitions in the partition table to work with any starting offset (:envvar:`CONFIG_PARTITION_TABLE_OFFSET`) of the table itself, leave the offset field (in CSV file) for all partitions blank. Similarly, if changing the partition table offset then be aware that all blank partition offsets may change to match, and that any fixed offsets may now collide with the partition table (causing an error).
+
+Flags
+~~~~~
+
+Only one flag is currently supported, ``encrypted``. If this field is set to ``encrypted``, this partition will be encrypted if :doc:`/security/flash-encryption` is enabled.
+
+(Note that ``app`` type partitions will always be encrypted, regardless of whether this flag is set or not.)
+
 Generating Binary Partition Table
 ---------------------------------
 
index 9f913ff814c93474380fc14c8e8694f7a25b0fdb..a712b8ec023c2fca6eb231c4a033b1aa2fc93be2 100644 (file)
@@ -15,8 +15,8 @@ Installing the toolchain
 
 ULP coprocessor code is written in assembly and compiled using the `binutils-esp32ulp toolchain`_.
 
-1. Download the toolchain using the links listed on this page:
-https://github.com/espressif/binutils-esp32ulp/wiki#downloads
+1. Download pre-built binaries of the latest toolchain release from:
+https://github.com/espressif/binutils-esp32ulp/releases.
 
 2. Extract the toolchain into a directory, and add the path to the ``bin/`` directory of the toolchain to the ``PATH`` environment variable.
 
@@ -134,7 +134,7 @@ Each ULP program is embedded into the ESP-IDF application as a binary blob. Appl
 
 Once the program is loaded into RTC memory, application can start it, passing the address of the entry point to ``ulp_run`` function::
 
-    ESP_ERROR_CHECK( ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t)) );
+    ESP_ERROR_CHECK( ulp_run(&ulp_entry - RTC_SLOW_MEM) );
 
 .. doxygenfunction:: ulp_run
 
index c4519d49d2c911b6297e49a2cc70406e2870a5db..71d35d83a0b88c115ccb134b4df6828e4718a450 100644 (file)
@@ -512,10 +512,29 @@ Note that when accessing RTC memories and RTC registers, ULP coprocessor has low
    - *Condition*:
        - *EQ* (equal) – jump if value in stage_cnt == threshold
        - *LT* (less than) –  jump if value in stage_cnt < threshold
+       - *LE* (less or equal) - jump if value in stage_cnt <= threshold
        - *GT* (greater than) –  jump if value in stage_cnt > threshold
+       - *GE* (greater or equal) — jump if value in stage_cnt >= threshold
 
 **Cycles**
-  2 cycles to execute, 2 cycles to fetch next instruction
+  Conditions *LE*, *LT*, *GE*: 2 cycles to execute, 2 cycles to fetch next instruction
+
+  Conditions *EQ*, *GT* are implemented in the assembler using two **JUMPS** instructions::
+
+    // JUMPS target, threshold, EQ is implemented as:
+
+             JUMPS next, threshold, LT
+             JUMPS target, threshold, LE
+    next:
+
+    // JUMPS target, threshold, GT is implemented as:
+    
+             JUMPS next, threshold, LE
+             JUMPS target, threshold, GE
+    next:
+
+  Therefore the execution time will depend on the branches taken: either 2 cycles to execute + 2 cycles to fetch, or 4 cycles to execute + 4 cycles to fetch.
+
 
 **Description**
     The instruction makes a jump to a relative address if condition is true. Condition is the result of comparison of count register value and threshold value.
index fe1f3b7438b1dfe36f473c601df4a800abad2f46..2ea0f71ab6b3cb5af723910d720d7d660c1c12d8 100644 (file)
@@ -1449,33 +1449,30 @@ Wi-Fi Channel State Information
 
 Channel state information (CSI) refers to the channel information of a Wi-Fi connection. In ESP32, this information consists of channel frequency responses of sub-carriers and is estimated when packets are received from the transmitter. Each channel frequency response of sub-carrier is recorded by two bytes of signed characters. The first one is imaginary part and the second one is real part. There are up to three fields of channel frequency responses according to the type of received packet. They are legacy long training field (LLTF), high throughput LTF (HT-LTF) and space time block code HT-LTF (STBC-HT-LTF). For different types of packets which are received on channels with different state, the sub-carrier index and total bytes of signed characters of CSI is shown in the following table.
 
-+-------------+--------------------+--------------------------------+---------------------------------------------------------------------------------------------------------------------+
-| packet      | signal mode        |             non HT             |                                                          HT                                                         |
-+             +--------------------+--------------------------------+---------------------------------+-------------------------------------------------------+---------------------------+
-| information | channel bandwidth  |              20MHz             |             20MHz               |                         40MHz                         |          20MHz            |
-+             +--------------------+--------------------------------+----------------+----------------+---------------------------+---------------------------+-------------+-------------+
-|             | STBC               |            non STBC            |    non STBC    |     STBC       |         non STBC          |           STBC            |   non STBC  |     STBC    |
-+-------------+--------------------+------------------+-------------+----------------+----------------+---------------------------+---------------------------+-------------+-------------+
-| channel     | HT20/40            |       HT40       |     HT20    |                                           HT40                                          |            HT20           |
-+             +--------------------+----------+-------+-------------+--------+-------+--------+-------+-------------+-------------+-------------+-------------+---------------------------+
-| information | secondary channel  |  below   | above |    none     | below  | above | below  | above |    below    |    above    |    below    |    above    |           none            |
-+-------------+--------------------+----------+-------+-------------+--------+-------+--------+-------+-------------+-------------+-------------+-------------+-------------+-------------+
-| sub-carrier | LLTF               | -64~-1   |  0~63 | 0~31,-31~-1 | -64~-1 | 0~63  | -64~-1 |  0~63 |    -64~-1   |     0~63    |    -64~-1   |     0~63    | 0~31,-31~-1 | 0~31,-31~-1 |
-+             +--------------------+----------+-------+-------------+--------+-------+--------+-------+-------------+-------------+-------------+-------------+-------------+-------------+
-| index       | HT-LTF             |     -    |   -   |      -      | -64~-1 | 0~63  | -62~-1 |  0~62 | 0~63,-64~-1 | 0~63,-64~-1 | 0~60,-60~-1 | 0~60,-60~-1 | 0~31,-31~-1 | 0~31,-31~-1 |
-+             +--------------------+----------+-------+-------------+--------+-------+--------+-------+-------------+-------------+-------------+-------------+-------------+-------------+
-|             | STBC-HT-LTF        |     -    |   -   |      -      |   -    |  -    | -62~-1 |  0~62 |      -      |       -     | 0~60,-60~-1 | 0~60,-60~-1 |      -      | 0~31,-31~-1 |
-+-------------+--------------------+----------+-------+-------------+--------+-------+--------+-------+-------------+-------------+-------------+-------------+-------------+-------------+
-| total bytes                      |    128   |  128  |      128    |   256  |  256  |   376  |  380  |     384     |      384    |      612    |     612     |      256    |      384    |
-+----------------------------------+----------+-------+-------------+--------+-------+--------+-------+-------------+-------------+-------------+-------------+-------------+-------------+
++-------------+--------------------+-----------------------------------------+--------------------------------------------------------+----------------------------------------------------------+
+| channel     | secondary channel  |                   none                  |                           above                        |                            below                         |
++-------------+--------------------+-------------+---------------------------+----------+---------------------------------------------+----------+-----------------------------------------------+
+| packet      | signal mode        |   non HT    |            HT             |  non HT  |                      HT                     |  non HT  |                       HT                      |
++             +--------------------+-------------+---------------------------+----------+-----------------+---------------------------+----------+-------------------+---------------------------+
+| information | channel bandwidth  |    20MHz    |           20MHz           |   20MHz  |      20MHz      |            40MHz          |   20MHz  |       20MHz       |            40MHz          |
++             +--------------------+-------------+-------------+-------------+----------+----------+------+-------------+-------------+----------+----------+--------+-------------+-------------+
+|             | STBC               |  non STBC   |  non STBC   |     STBC    | non STBC | non STBC | STBC |  non STBC   |     STBC    | non STBC | non STBC |  STBC  |  non STBC   |     STBC    |
++-------------+--------------------+-------------+-------------+-------------+----------+----------+------+-------------+-------------+----------+----------+--------+-------------+-------------+
+| sub-carrier | LLTF               | 0~31,-31~-1 | 0~31,-31~-1 | 0~31,-31~-1 |   0~63   |   0~63   | 0~63 |     0~63    |     0~63    |  -64~-1  |  -64~-1  | -64~-1 |    -64~-1   |    -64~-1   |
++             +--------------------+-------------+-------------+-------------+----------+----------+------+-------------+-------------+----------+----------+--------+-------------+-------------+
+| index       | HT-LTF             |      -      | 0~31,-31~-1 | 0~31,-31~-1 |     -    |   0~63   | 0~62 | 0~63,-64~-1 | 0~60,-60~-1 |     -    |  -64~-1  | -62~-1 | 0~63,-64~-1 | 0~60,-60~-1 |
++             +--------------------+-------------+-------------+-------------+----------+----------+------+-------------+-------------+----------+----------+--------+-------------+-------------+
+|             | STBC-HT-LTF        |      -      |      -      | 0~31,-31~-1 |     -    |     -    | 0~62 |       -     | 0~60,-60~-1 |     -    |     -    | -62~-1 |       -     | 0~60,-60~-1 |
++-------------+--------------------+-------------+-------------+-------------+----------+----------+------+-------------+-------------+----------+----------+--------+-------------+-------------+
+| total bytes                      |     128     |     256     |     384     |    128   |    256   | 380  |      384    |      612    |    128   |    256   |   376  |      384    |      612    |
++----------------------------------+-------------+-------------+-------------+----------+----------+------+-------------+-------------+----------+----------+--------+-------------+-------------+
 
 All of the information in the table can be found in the structure wifi_csi_info_t. 
 
+    - Secondary channel refers to secondary_channel field of rx_ctrl field. 
     - Signal mode of packet refers to sig_mode field of rx_ctrl field. 
     - Channel bandwidth refers to cwb field of rx_ctrl field. 
     - STBC refers to stbc field of rx_ctrl field. 
-    - HT20/40 depends on secondary channel. If secondary channel is above or below primary channel, it is HT40. If secondary channel is none, it is HT20. 
-    - Secondary channel refers to secondary_channel field of rx_ctrl field. 
     - Total bytes refers to len field. 
     - The CSI data corresponding to each Long Training Field type is stored in a buffer starting from the buf field. Each item is stored as two bytes: imaginary part followed by real part. The order is: LLTF, HT-LTF, STBC-HT-LTF. However all 3 items may not be present, depending on the packet type (see above).
     - If last_word_invalid field of wifi_csi_info_t is true, it means that the last four bytes of CSI data is invalid due to a hardware limitation in ESP32. 
@@ -1484,7 +1481,7 @@ All of the information in the table can be found in the structure wifi_csi_info_
 .. note::
 
     - For STBC packet, CSI is provided for every space-time stream without CSD (cyclic shift delay). As each cyclic shift on the additional chains shall be -200ns, only the CSD angle of first space-time stream is recorded in sub-carrier 0 of HT-LTF and STBC-HT-LTF for there is no channel frequency response in sub-carrier 0. CSD[10:0] is 11 bits, ranging from -pi to pi.
-    - If LLTF, HT-LTF or STBC-HT-LTF is not enabled by calling API :cpp:func:`esp_wifi_set_csi_config`, the total bytes of CSI data will be fewer than that in the table. For example, if LLTF and HT-LTF is not enabled and STBC-HT-LTF is enabled, when a packet is received with the condition HT/HT40/40MHz/STBC/above, the total bytes of CSI data is 244 ((61 + 60) * 2 + 2 = 244, the result is aligned to four bytes and the last two bytes is invalid). 
+    - If LLTF, HT-LTF or STBC-HT-LTF is not enabled by calling API :cpp:func:`esp_wifi_set_csi_config`, the total bytes of CSI data will be fewer than that in the table. For example, if LLTF and HT-LTF is not enabled and STBC-HT-LTF is enabled, when a packet is received with the condition above/HT/40MHz/STBC, the total bytes of CSI data is 244 ((61 + 60) * 2 + 2 = 244, the result is aligned to four bytes and the last two bytes is invalid). 
 
 Wi-Fi Channel State Information Configure
 -------------------------------------------
index 972c1f0c9a8e5ff4c7c72decdfe72020f6d2cabd..55b613a8cefd3b36e355e1078c383bd00ffac8bc 100644 (file)
@@ -4,16 +4,15 @@ Analog to Digital Converter
 Overview
 --------
 
-ESP32 integrates two 12-bit SAR (`Successive Approximation Register <https://en.wikipedia.org/wiki/Successive_approximation_ADC>`_) ADCs (Analog to Digital Converters) and supports measurements on 18 channels (analog enabled pins). Some of these pins can be used to build a programmable gain amplifier which is used for the measurement of small analog signals.
+The ESP32 integrates two 12-bit SAR (`Successive Approximation Register <https://en.wikipedia.org/wiki/Successive_approximation_ADC>`_) ADCs supporting a total of 18 measurement channels (analog enabled pins).
 
-The ADC driver API supports ADC1 (8 channels, attached to GPIOs 32 - 39), and ADC2 (10 channels, attached to GPIOs 0, 2, 4, 12 - 15 and 25 - 27).
-However, there're some restrictions for the application to use ADC2:
+The ADC driver API supports ADC1 (8 channels, attached to GPIOs 32 - 39), and ADC2 (10 channels, attached to GPIOs 0, 2, 4, 12 - 15 and 25 - 27). However, the usage of ADC2 has some restrictions for the application:
 
-1. The application can use ADC2 only when Wi-Fi driver is not started, since the ADC is also used by the Wi-Fi driver, which has higher priority.
-2. Some of the ADC2 pins are used as strapping pins (GPIO 0, 2, 15), so they cannot be used freely. For examples, for official Develop Kits:
+1. ADC2 is used by the Wi-Fi driver. Therefore the application can only use ADC2 when the Wi-Fi driver has not started.
+2. Some of the ADC2 pins are used as strapping pins (GPIO 0, 2, 15) thus cannot be used freely. Such is the case in the following official Development Kits:
 
-  - :ref:`ESP32 Core Board V2 / ESP32 DevKitC <esp-modules-and-boards-esp32-devkitc>`: GPIO 0 cannot be used due to external auto program circuits.
-  - :ref:`ESP-WROVER-KIT V3 <esp-modules-and-boards-esp-wrover-kit-v3>`: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes.
+  - :ref:`ESP32 DevKitC <esp-modules-and-boards-esp32-devkitc>`: GPIO 0 cannot be used due to external auto program circuits.
+  - :ref:`ESP-WROVER-KIT <esp-modules-and-boards-esp-wrover-kit>`: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes.
 
 Configuration and Reading ADC
 -----------------------------
@@ -29,7 +28,7 @@ Then it is possible to read ADC conversion result with :cpp:func:`adc1_get_raw`
 
 .. note:: Since the ADC2 is shared with the WIFI module, which has higher priority, reading operation of :cpp:func:`adc2_get_raw` will fail between :cpp:func:`esp_wifi_start()` and :cpp:func:`esp_wifi_stop()`. Use the return code to see whether the reading is successful.
 
-It is also possible to read the internal hall effect sensor via ADC1 by calling dedicated function :cpp:func:`hall_sensor_read`. Note that even the hall sensor is internal to ESP32, reading from it uses channels 0 and 3 of ADC1 (GPIO 36 and 39). Do not connect anything else to these pins and do not change their configuration. Otherwise it may affect the measurement of low value signal from the sesnor.
+It is also possible to read the internal hall effect sensor via ADC1 by calling dedicated function :cpp:func:`hall_sensor_read`. Note that even the hall sensor is internal to ESP32, reading from it uses channels 0 and 3 of ADC1 (GPIO 36 and 39). Do not connect anything else to these pins and do not change their configuration. Otherwise it may affect the measurement of low value signal from the sensor.
 
 This API provides convenient way to configure ADC1 for reading from :doc:`ULP <../../api-guides/ulp>`. To do so, call function :cpp:func:`adc1_ulp_enable` and then set precision and attenuation as discussed above.
 
diff --git a/docs/en/api-reference/system/esp_https_ota.rst b/docs/en/api-reference/system/esp_https_ota.rst
new file mode 100644 (file)
index 0000000..762de6c
--- /dev/null
@@ -0,0 +1,35 @@
+ESP HTTPS OTA
+=============
+
+Overview
+--------
+
+``esp_https_ota`` provides simplified APIs to perform firmware upgrades over HTTPS.
+It's an abstraction layer over existing OTA APIs.
+
+Application Example
+-------------------
+
+    .. highlight:: c
+
+    ::
+
+        esp_err_t do_firmware_upgrade()
+        {
+            esp_http_client_config_t config = {
+                .url = CONFIG_FIRMWARE_UPGRADE_URL,
+                .cert_pem = (char *)server_cert_pem_start,
+            };
+            esp_err_t ret = esp_https_ota(&config);
+            if (ret == ESP_OK) {
+                esp_restart();
+            } else {
+                return ESP_FAIL;
+            }
+            return ESP_OK;
+        }
+
+API Reference
+-------------
+
+.. include:: /_build/inc/esp_https_ota.inc
index 7769d1cf69ee17671a0feb605c1c16684e2c63d6..453b73e70f06a655f37008202c9ee63d8e368f75 100644 (file)
@@ -4,7 +4,7 @@ Heap Memory Debugging
 Overview
 --------
 
-ESP-IDF integrates tools for requesting `heap information`_, `detecting heap corruption <heap corruption detection>`_, and `tracing memory leaks <heap tracing>`_. These can help track down memory-related bugs.
+ESP-IDF integrates tools for requesting :ref:`heap information <heap-information>`, :ref:`detecting heap corruption <heap-corruption>`, and :ref:`tracing memory leaks <heap-tracing>`. These can help track down memory-related bugs.
 
 For general information about the heap memory allocator, see the :doc:`Heap Memory Allocation </api-reference/system/mem_alloc>` page.
 
@@ -136,7 +136,7 @@ Heap tracing can perform two functions:
 How To Diagnose Memory Leaks
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-If you suspect a memory leak, the first step is to figure out which part of the program is leaking memory. Use the :cpp:func:`xPortGetFreeHeapSize`, :cpp:func:`heap_caps_get_free`, and related functions to track memory use over the life of the application. Try to narrow the leak down to a single function or sequence of functions where free memory always decreases and never recovers.
+If you suspect a memory leak, the first step is to figure out which part of the program is leaking memory. Use the :cpp:func:`xPortGetFreeHeapSize`, :cpp:func:`heap_caps_get_free_size`, or :ref:`related functions <heap-information>` to track memory use over the life of the application. Try to narrow the leak down to a single function or sequence of functions where free memory always decreases and never recovers.
 
 Once you've identified the code which you think is leaking:
 
@@ -211,13 +211,11 @@ A warning will be printed if the trace buffer was not large enough to hold all t
 Heap Tracing To Find Heap Corruption
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-When a region in heap is corrupted, it may be from some other part of the program which allocated memory at a nearby address.
+Heap tracing can also be used to help track down heap corruption. When a region in heap is corrupted, it may be from some other part of the program which allocated memory at a nearby address.
 
-If you have some idea at what time the corruption occured, enabling heap tracing in ``HEAP_TRACE_ALL`` mode allows you to record all of the functions which allocated memory, and the addresses where they were corrupted.
+If you have some idea at what time the corruption occurred, enabling heap tracing in ``HEAP_TRACE_ALL`` mode allows you to record all of the functions which allocated memory, and the addresses of the allocations.
 
-Using heap tracing in this way is very similar to memory leak detection as described above. For memory which is allocated and not freed, the output 
-
-Heap tracing can also be used to help track down heap corruption. By using 
+Using heap tracing in this way is very similar to memory leak detection as described above. For memory which is allocated and not freed, the output is the same. However, records will also be shown for memory which has been freed.
 
 Performance Impact
 ^^^^^^^^^^^^^^^^^^
@@ -234,6 +232,7 @@ Not everything printed by :cpp:func:`heap_trace_dump` is necessarily a memory le
 - Any memory which is allocated after :cpp:func:`heap_trace_start` but then freed after :cpp:func:`heap_trace_stop` will appear in the leak dump.
 - Allocations may be made by other tasks in the system. Depending on the timing of these tasks, it's quite possible this memory is freed after :cpp:func:`heap_trace_stop` is called.
 - The first time a task uses stdio - for example, when it calls ``printf()`` - a lock (RTOS mutex semaphore) is allocated by the libc. This allocation lasts until the task is deleted.
+- Certain uses of ``printf()``, such as printing floating point numbers, will allocate some memory from the heap on demand. These allocations last until the task is deleted.
 - The Bluetooth, WiFi, and TCP/IP libraries will allocate heap memory buffers to handle incoming or outgoing data. These memory buffers are usually short lived, but some may be shown in the heap leak trace if the data was received/transmitted by the lower levels of the network while the leak trace was running.
 - TCP connections will continue to use some memory after they are closed, because of the ``TIME_WAIT`` state. After the ``TIME_WAIT`` period has completed, this memory will be freed.
 
index d9a32fd4e4d889a6e9a48fb55350f2c4208bccef..2b94e6d550889270695d76da19bd9c0ad28e5c7e 100644 (file)
@@ -18,6 +18,7 @@ System API
    Sleep Modes <sleep_modes>
    Base MAC address <base_mac_address>
    Over The Air Updates (OTA) <ota>
+   ESP HTTPS OTA <esp_https_ota>
    ESP pthread <esp_pthread>
    Error Codes and Helper Functions <esp_err>
 
index d7dbb5978c3fa7625075a3b0ed0dae74f5ad8ad2..82533547364201b99725100bb802e9911211ac02 100644 (file)
@@ -37,6 +37,7 @@ See also
 
 * :doc:`Partition Table documentation <../../api-guides/partition-tables>`
 * :doc:`Lower-Level SPI Flash/Partition API <../storage/spi_flash>`
+* :doc:`ESP HTTPS OTA <esp_https_ota>`
 
 Application Example
 -------------------
index e54345d83148bd6b00bfaa4c5abe2379a248e787..8a337af8f5d8a9530843be7f0dd6b421aa6cba30 100644 (file)
@@ -10,13 +10,31 @@ Connect ESP32 to PC
 
 Connect the ESP32 board to the PC using the USB cable. If device driver does not install automatically, identify USB to serial converter chip on your ESP32 board (or external converter dongle), search for drivers in internet and install them.
 
-Below are the links to drivers for ESP32 boards produced by Espressif:
+Below are the links to drivers for ESP32 and other boards produced by Espressif:
 
-* ESP32-PICO-KIT and ESP32-DevKitC - `CP210x USB to UART Bridge VCP Drivers <https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers>`_
 
-* ESP32-WROVER-KIT and ESP32 Demo Board - `FTDI Virtual COM Port Drivers <http://www.ftdichip.com/Drivers/VCP.htm>`_
+.. csv-table::
+    :header: Development Board, USB Driver, Remarks
+    :widths: 40, 20, 40
 
-Above drivers are primarily for reference. They should already be bundled with the operating system and installed automatically once one of listed boards is connected to the PC.
+    :ref:`ESP32-DevKitC <esp-modules-and-boards-esp32-devkitc>`,  `CP210x`_
+    `ESP32-LyraT <https://www.espressif.com/en/products/hardware/esp32-lyrat>`_, `CP210x`_
+    `ESP32-LyraTD-MSC <https://www.espressif.com/en/products/hardware/esp32-lyratd-msc>`_, `CP210x`_
+    :ref:`ESP32-PICO-KIT <esp-modules-and-boards-esp32-pico-kit>`, `CP210x`_
+    :ref:`ESP-WROVER-KIT <esp-modules-and-boards-esp-wrover-kit>`, `FTDI`_
+    :ref:`ESP32 Demo Board <esp-modules-and-boards-esp32-demo-board>`, `FTDI`_
+    `ESP-Prog`_, `FTDI`_, Programmer board (w/o ESP32)
+    `ESP32-MeshKit-Sense <https://github.com/espressif/esp-iot-solution/blob/master/documents/evaluation_boards/ESP32-MeshKit-Sense_guide_en.md#esp32-meshkit-sense-hardware-design-guidelines>`_, n/a, Use with `ESP-Prog`_
+    `ESP32-Sense Kit <https://github.com/espressif/esp-iot-solution/blob/master/documents/evaluation_boards/esp32_sense_kit_guide_en.md#guide-for-esp32-sense-development-kit>`_, n/a, Use with `ESP-Prog`_
+
+.. _CP210x: https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers
+.. _FTDI: http://www.ftdichip.com/Drivers/VCP.htm 
+.. _ESP-Prog: https://github.com/espressif/esp-iot-solution/blob/master/documents/evaluation_boards/ESP-Prog_guide_en.md#introduction-to-the-esp-prog-board
+
+* CP210x: `CP210x USB to UART Bridge VCP Drivers <https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers>`_ 
+* FTDI: `FTDI Virtual COM Port Drivers <http://www.ftdichip.com/Drivers/VCP.htm>`_
+
+The drivers above are primarily for reference. Under normal circumstances, the drivers should be bundled with and operating system and automatically installed upon connecting one of the listed boards to the PC.
 
 
 Check port on Windows
index 0cbbe2c286bd4ec887dfa7ed6285b2c047210f91..188b6938d44cdbf3061c2e8ec3b02c65d4adfa53 100644 (file)
@@ -5,6 +5,7 @@ Get Started
 \r
 This document is intended to help users set up the software environment for development of applications using hardware based on the Espressif ESP32. Through a simple example we would like to illustrate how to use ESP-IDF (Espressif IoT Development Framework), including the menu based configuration, compiling the ESP-IDF and firmware download to ESP32 boards. \r
 \r
+.. include:: /_build/inc/version-note.inc\r
 \r
 Introduction\r
 ============\r
@@ -114,19 +115,18 @@ Get ESP-IDF
 \r
 .. highlight:: bash\r
 \r
-Besides the toolchain (that contains programs to compile and build the application), you also need ESP32 specific API / libraries. They are provided by Espressif in `ESP-IDF repository <https://github.com/espressif/esp-idf>`_. To get it, open terminal, navigate to the directory you want to put ESP-IDF, and clone it using ``git clone`` command::\r
+Besides the toolchain (that contains programs to compile and build the application), you also need ESP32 specific API / libraries. They are provided by Espressif in `ESP-IDF repository <https://github.com/espressif/esp-idf>`_.\r
 \r
-    cd ~/esp\r
-    git clone --recursive https://github.com/espressif/esp-idf.git\r
+.. include:: /_build/inc/git-clone.inc\r
 \r
-ESP-IDF will be downloaded into ``~/esp/esp-idf``.\r
+Consult :doc:`/versions` for information about which version of ESP-IDF to use in a given situation.\r
 \r
 .. note::\r
 \r
     Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules::\r
 \r
         cd ~/esp/esp-idf\r
-        git submodule update --init\r
+        git submodule update --init --recursive\r
 \r
 \r
 .. _get-started-setup-path:\r
@@ -300,23 +300,9 @@ Updating ESP-IDF
 \r
 After some time of using ESP-IDF, you may want to update it to take advantage of new features or bug fixes. The simplest way to do so is by deleting existing ``esp-idf`` folder and cloning it again, exactly as when doing initial installation described in sections :ref:`get-started-get-esp-idf`.\r
 \r
-Another solution is to update only what has changed. This method is useful if you have a slow connection to GitHub. To do the update run the following commands::\r
-\r
-    cd ~/esp/esp-idf\r
-    git pull\r
-    git submodule update --init --recursive\r
-\r
-The ``git pull`` command is fetching and merging changes from ESP-IDF repository on GitHub. Then ``git submodule update --init --recursive`` is updating existing submodules or getting a fresh copy of new ones. On GitHub the submodules are represented as links to other repositories and require this additional command to get them onto your PC.\r
-\r
-If you would like to use specific release of ESP-IDF, e.g. `v2.1`, run::\r
+If downloading to a new path, remember to :doc:`add-idf_path-to-profile` so that the toolchain scripts know where to find the ESP-IDF in its release specific location.\r
 \r
-    cd ~/esp\r
-    git clone https://github.com/espressif/esp-idf.git esp-idf-v2.1\r
-    cd esp-idf-v2.1/\r
-    git checkout v2.1\r
-    git submodule update --init --recursive\r
-\r
-After that remember to :doc:`add-idf_path-to-profile`, so the toolchain scripts know where to find the ESP-IDF in it's release specific location.\r
+Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using <updating>`.\r
 \r
 \r
 Related Documents\r
@@ -331,3 +317,7 @@ Related Documents
     eclipse-setup\r
     idf-monitor\r
     toolchain-setup-scratch\r
+\r
+.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/\r
+.. _Releases page: https://github.com/espressif/esp-idf/releases\r
+\r
index 8044b7df0cc929a54c37f97caa05910cf2ebc6c3..863955e797ba963fbb2c2fdadfc48c3b3d1221ed 100644 (file)
@@ -8,8 +8,7 @@ This sections contains overview and links to documentation of previous version E
 
 To see the latest development boards, please refer to section :ref:`esp-modules-and-boards`.
 
-
-.. _esp-modules-and-boards-esp32-pico-pit-v4:
+.. _esp-modules-and-boards-esp32-pico-kit-v4:
 
 ESP32-PICO-KIT V4
 =================
@@ -32,7 +31,7 @@ Documentation
 * `ESP32-PICO-KIT V4 Schematic <https://dl.espressif.com/dl/schematics/esp32-pico-kit-v4_schematic.pdf>`_ (PDF)
 * `ESP32-PICO-D4 Datasheet <http://espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf>`_ (PDF)
 
-.. _esp-modules-and-boards-esp32-pico-pit-v3:
+.. _esp-modules-and-boards-esp32-pico-kit-v3:
 
 ESP32-PICO-KIT V3
 =================
@@ -130,7 +129,7 @@ Documentation
 * `FTDI Virtual COM Port Drivers`_
 
 
-.. _esp-modules-and-boards-esp32-demo-board-v2:
+.. _esp-modules-and-boards-esp32-demo-board:
 
 ESP32 Demo Board V2
 ===================
index 24567517245f84ade081c01f0bb9b67fb0f6601d..c786aac8d6780547b9ba9cff070563e99f260941 100644 (file)
@@ -123,7 +123,7 @@ Documentation
 * `ESP32-WROVER Reference Design <https://www.espressif.com/en/support/download/documents?keys=ESP32-WROVER+Reference+Design>`_ containing OrCAD schematic, PCB layout, gerbers and BOM
 
 
-.. _esp-modules-and-boards-esp32-pico-pit-v4.1:
+.. _esp-modules-and-boards-esp32-pico-kit:
 
 ESP32-PICO-KIT V4.1
 ===================
@@ -150,8 +150,8 @@ Documentation
 Previous Versions
 -----------------
 
-* :ref:`esp-modules-and-boards-esp32-pico-pit-v4`
-* :ref:`esp-modules-and-boards-esp32-pico-pit-v3`
+* :ref:`esp-modules-and-boards-esp32-pico-kit-v4`
+* :ref:`esp-modules-and-boards-esp32-pico-kit-v3`
 
 
 .. _esp-modules-and-boards-esp32-devkitc:
@@ -182,7 +182,7 @@ Previous Versions
 * :ref:`esp-modules-and-boards-esp32-devkitc-v2`
 
 
-.. _esp-modules-and-boards-esp-wrover-kit-v3:
+.. _esp-modules-and-boards-esp-wrover-kit:
 
 ESP-WROVER-KIT V3
 =================
index 80079de3db64154e28c619b650f0004911e30d1b..d7295b4fade8117c0e67cbcd803b6596490c56cc 100644 (file)
@@ -44,9 +44,13 @@ The documentation has different language versions (:link_to_translation:`en:Engl
    H/W Reference <hw-reference/index>
    API Guides <api-guides/index>
    Contribute <contribute/index>
+   Versions <versions>
    Resources <resources>
    Copyrights <COPYRIGHT>
    About <about>
    [语言/Languages] <languages>
    
 * :ref:`genindex`
+
+
+
index 6981976a6ac172b46ef7953d968da021220d32e6..acc4b6b164cdc20d9a553395bbb010fecb0b4e1b 100644 (file)
@@ -23,7 +23,7 @@ Background
   - Secure boot bootloader digest (if secure boot is enabled)
   - Partition Table
   - All "app" type partitions
-  - Any partition marked with the "encrypt" flag in the partition table
+  - Any partition marked with the "encrypted" flag in the partition table
 
        It may be desirable for some data partitions to remain unencrypted for ease of access, or to use flash-friendly update algorithms that are ineffective if the data is encrypted. "NVS" partitions for non-volatile storage cannot be encrypted.
 
diff --git a/docs/en/versions.rst b/docs/en/versions.rst
new file mode 100644 (file)
index 0000000..5d6530c
--- /dev/null
@@ -0,0 +1,178 @@
+ESP-IDF Versions
+================
+
+The ESP-IDF GitHub repository is updated regularly, especially on the "master branch" where new development happens. There are also stable releases which are recommended for production use.
+
+Releases
+--------
+
+Documentation for the current stable version can always be found at this URL:
+
+https://docs.espressif.com/projects/esp-idf/en/stable/
+
+Documentation for the latest version ("master branch") can always be found at this URL:
+
+https://docs.espressif.com/projects/esp-idf/en/latest/
+
+The full history of releases can be found on the GitHub repository `Releases page`_. There you can find release notes, links to each version of the documentation, and instructions for obtaining each version.
+
+Documentation for all releases can also be found in the HTML documentation by clicking the "versions" pop up in the bottom-left corner of the page. You can use this popup to switch between versions of the documentation.
+
+.. image:: /../_static/choose_version.png
+
+Which Version Should I Start With?
+----------------------------------
+
+- For production purposes, use the `current stable version`_. Stable versions have been manually tested, and are updated with "bugfix releases" which fix bugs without changing other functionality (see `Versioning Scheme`_ for more details).
+
+- For prototyping, experimentation or for developing new ESP-IDF features, use the `latest version (master branch in Git) <https://docs.espressif.com/projects/esp-idf/en/latest/>`_. The latest version in the master branch has all the latest features and has passed automated testing, but has not been completely manually tested ("bleeding edge").
+
+- If a required feature is not yet available in a stable release, but you don't want to use the master branch, it is possible to check out a pre-release version or a release branch. It is recommended to start from a stable version and then follow the instructions for :ref:`updating-pre-release` or :ref:`updating-release-branch`.
+
+See :ref:`updating` if you already have a local copy of ESP-IDF and wish to update it.
+
+Versioning Scheme
+-----------------
+
+ESP-IDF uses `Semantic Versioning <http://semver.org/>`_. This means:
+
+- Major Releases like ``v3.0`` add new functionality and may change functionality. This includes removing deprecated functionality.
+
+  When updating to a new major release (for example, from ``v2.1`` to ``v3.0``), some of your project's code may need updating and functionality will need to be re-tested. The release notes on the `Releases page`_ include lists of Breaking Changes to refer to.
+- Minor Releases like ``v3.1`` add new functionality and fix bugs but will not change or remove documented functionality, or make incompatible changes to public APIs.
+
+  If updating to a new minor release (for example, from ``v3.0`` to ``v3.1``) then none of your project's code should need updating, but you should re-test your project. Pay particular attention to items mentioned in the release notes on the `Releases page`_.
+- Bugfix Releases like ``v3.0.1`` only fix bugs and do not add new functionality.
+
+  If updating to a new bugfix release (for example, from ``v3.0`` to ``v3.0.1``), you should not need to change any code in your project and should only need to re-test functionality relating directly to bugs listed in the release notes on the `Releases page`_.
+
+Checking The Current Version
+----------------------------
+
+The local ESP-IDF version can be checked using git::
+
+  cd $IDF_PATH
+  git describe --tags --dirty
+
+The version is also compiled into the firmware and can be accessed (as a string) via the macro ``IDF_VER``. The default ESP-IDF bootloader will print the version on boot (these versions in code will not always update, it only changes if that particular source file is recompiled).
+
+Examples of ESP-IDF versions:
+
+============================ ==================================================
+Version String               Meaning
+============================ ==================================================
+``v3.2-dev-306-gbeb3611ca``  Master branch pre-release, in development for
+                             version 3.2. 306 commits after v3.2 development
+                             started. Commit identifier ``beb3611ca``.
+``v3.0.2``                   Stable release, tagged ``v3.0.2``.
+``v3.1-beta1-75-g346d6b0ea`` Beta version in development (on a
+                             :ref:`release branch <updating-release-branch>`).
+                             75 commits after ``v3.1-beta1`` pre-release tag.
+                             Commit identifier ``346d6b0ea``.
+``v3.0.1-dirty``             Stable release, tagged ``v3.0.1``.
+                             There are modifications in the local ESP-IDF
+                             directory ("``dirty``").
+============================ ==================================================
+
+
+
+Git Workflow
+------------
+
+The development (Git) workflow of the Espressif ESP-IDF team is:
+
+- New work is always added on the master branch (latest version) first. The ESP-IDF version on ``master`` is always tagged with ``-dev`` (for "in development"), for example ``v3.1-dev``.
+- Changes are first added to an internal Git repository for code review and testing, but are pushed to GitHub after automated testing passes.
+- When a new version (developed on ``master``) becomes feature complete and "beta" quality, a new branch is made for the release, for example ``release/v3.1``. A pre-release tag is also created, for example ``v3.1-beta1``. You can see a full `list of branches`_ and a `list of tags`_ on GitHub. Beta pre-releases have release notes which may include a significant number of Known Issues.
+- As testing of the beta version progresses, bug fixes will be added to both the ``master`` branch and the release branch. New features (for the next release) may start being added to ``master`` at the same time.
+- Once testing is nearly complete a new release candidate is tagged on the release branch, for example ``v3.1-rc1``. This is still a pre-release version.
+- If no more significant bugs are found or reported then the final Major or Minor Version is tagged, for example ``v3.1``. This version appears on the `Releases page`_.
+- As bugs are reported in released versions, the fixes will continue to be committed to the same release branch.
+- Regular bugfix releases are made from the same release branch. After manual testing is complete, a bugfix release is tagged (i.e. ``v3.1.1``) and appears on the `Releases page`_.
+
+.. _updating:
+
+Updating ESP-IDF
+----------------
+
+Updating ESP-IDF depends on which version(s) you wish to follow:
+
+- :ref:`updating-stable-releases` is recommended for production use.
+- :ref:`updating-master` is recommended for latest features, development use, and testing.
+- :ref:`updating-release-branch` is a compromise between these two.
+
+.. note:: These guides assume you already have a local copy of ESP-IDF. To get one, follow the :doc:`Getting Started </get-started/index>` guide for any ESP-IDF version.
+
+.. _`updating-stable-releases`:
+
+Updating to Stable Release
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To update to new ESP-IDF releases (recommended for production use), this is the process to follow:
+
+- Check the `Releases page`_ regularly for new releases.
+- When a bugfix release for a version you are using is released (for example if using ``v3.0.1`` and ``v3.0.2`` is available), check out the new bugfix version into the existing ESP-IDF directory::
+
+    cd $IDF_PATH
+    git fetch
+    git checkout vX.Y.Z
+    git submodule update --init --recursive
+- When major or minor updates are released, check the Release Notes  on the releases page and decide if you would like to update or to stay with your existing release. Updating is via the same Git commands shown above.
+
+.. note:: If you installed the stable release via zip file rather than using git, it may not be possible to change versions this way. In this case, update by downloading a new zip file and replacing the entire ``IDF_PATH`` directory with its contents.
+
+
+.. _`updating-pre-release`:
+
+Updating to a Pre-Release Version
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+It is also possible to ``git checkout`` a tag corresponding to a pre-release version or release candidate, the process is the same as :ref:`updating-stable-releases`.
+
+Pre-release tags are not always found on the `Releases page`_. Consult the `list of tags`_ on GitHub for a full list. Caveats for using a pre-release are similar to :ref:`updating-release-branch`.
+
+.. _`updating-master`:
+
+Updating to Master Branch
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. note:: Using Master branch means living "on the bleeding edge" with the latest ESP-IDF code.
+
+To use the latest version on the ESP-IDF master branch, this is the process to follow:
+
+- Check out the master branch locally::
+
+    cd $IDF_PATH
+    git checkout master
+    git pull
+    git submodule update --init --recursive
+- Periodically, re-run ``git pull`` to pull the latest version of master. Note that you may need to change your project or report bugs after updating master branch.
+- To switch from ``master`` to a release branch or stable version, run ``git checkout`` as shown in the other sections.
+
+.. important:: It is strongly recommended to regularly run ``git pull`` and then ``git submodule update --init --recursive`` so a local copy of ``master`` does not get too old. Arbitrary old master branch revisions are effectively unsupportable "snapshots" that may have undocumented bugs. For a semi-stable version, try :ref:`updating-release-branch` instead.
+
+.. _`updating-release-branch`:
+
+Updating to a Release Branch
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In stability terms, using a release branch is part-way between using ``master`` branch and only using stable releases. A release branch is always beta quality or better, and receives bug fixes before they appear in each stable release.
+
+You can find a `list of branches`_ on GitHub.
+
+For example, to follow the branch for ESP-IDF v3.1, including any bugfixes for future releases like ``v3.1.1``, etc::
+
+  cd $IDF_PATH
+  git fetch
+  git checkout release/v3.1
+  git pull
+  git submodule --update --init --recursive
+
+Each time you ``git pull`` this branch, ESP-IDF will be updated with fixes for this release.
+
+.. note:: The is no dedicated documentation for release branches. It is recommended to use the documentation for the closest version to the branch which is currently checked out.
+
+.. _`Releases page`: http://github.com/espressif/esp-idf/releases
+.. _`list of branches`: https://github.com/espressif/esp-idf/branches
+.. _`list of tags`: https://github.com/espressif/esp-idf/tags
+.. _`current stable version`: https://docs.espressif.com/projects/esp-idf/en/stable/
diff --git a/docs/gen-version-specific-includes.py b/docs/gen-version-specific-includes.py
new file mode 100755 (executable)
index 0000000..a295e4b
--- /dev/null
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Python script to generate ReSTructured Text .inc snippets
+# with version-based content for this IDF version
+
+import subprocess
+import os
+import sys
+import re
+
+TEMPLATES = {
+    "en" : {
+        "git-clone" : {
+            "template" : """
+To obtain a local copy: open terminal, navigate to the directory you want to put ESP-IDF, and clone the repository using ``git clone`` command::
+
+    cd ~/esp
+    git clone %(clone_args)s--recursive https://github.com/espressif/esp-idf.git
+
+ESP-IDF will be downloaded into ``~/esp/esp-idf``.
+
+.. note::
+
+    %(extra_note)s
+
+.. note::
+
+    %(zipfile_note)s
+"""
+            ,"master" : 'This command will clone the master branch, which has the latest development ("bleeding edge") version of ESP-IDF. It is fully functional and updated on weekly basis with the most recent features and bugfixes.'
+            ,"branch" : 'The ``git clone`` option ``-b %(clone_arg)s`` tells git to clone the %(ver_type)s in the ESP-IDF repository corresponding to this version of the documentation.'
+            ,"zipfile" : {
+                "stable" : 'As a fallback, it is also possible to download a zip file of this stable release from the `Releases page`_. Do not download the "Source code" zip file(s) generated automatically by GitHub, they do not work with ESP-IDF.'
+                ,"unstable" : 'GitHub\'s "Download zip file" feature does not work with ESP-IDF, a ``git clone`` is required. As a fallback, `Stable version`_ can be installed without Git.'
+                },  # zipfile
+            },  # git-clone
+        "version-note" : {
+            "master" : """
+.. note::
+     This is documentation for the master branch (latest version) of ESP-IDF. This version is under continual development. `Stable version`_ documentation is available, as well as other :doc:`/versions`.
+"""
+            ,"stable" : """
+.. note::
+     This is documentation for stable version %s of ESP-IDF. Other :doc:`/versions` are also available.
+"""
+            ,"branch" : """
+.. note::
+     This is documentation for %s ``%s`` of ESP-IDF. Other :doc:`/versions` are also available.
+"""
+            },  # version-note
+    }, # en
+    "zh_CN" : {
+        "git-clone" : {
+            "template" : """
+获取本地副本:打开终端,切换到你要存放 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库::
+
+    cd ~/esp
+    git clone %(clone_args)s--recursive https://github.com/espressif/esp-idf.git
+
+ESP-IDF 将会被下载到 ``~/esp/esp-idf`` 目录下。
+
+.. note::
+
+    %(extra_note)s
+
+.. note::
+
+    %(zipfile_note)s
+"""
+            ,"master" : '此命令将克隆 master 分支,该分支保存着 ESP-IDF 的最新版本,它功能齐全,每周都会更新一些新功能并修正一些错误。'
+            ,"branch" : '``git clone`` 命令的 ``-b %(clone_arg)s`` 选项告诉 git 从 ESP-IDF 仓库中克隆与此版本的文档对应的分支。'
+            ,"zipfile" : {
+                "stable" : '作为备份,还可以从 `Releases page`_ 下载此稳定版本的 zip 文件。不要下载由 GitHub 自动生成的"源代码"的 zip 文件,它们不适用于 ESP-IDF。'
+                ,"unstable" : 'GitHub 中"下载 zip 文档"的功能不适用于 ESP-IDF,所以需要使用 ``git clone`` 命令。作为备份,可以在没有安装 Git 的环境中下载 `Stable version`_ 的 zip 归档文件。'
+                },  # zipfile
+            },  # git-clone
+        "version-note" : {
+            "master" : """
+.. note::
+     这是ESP-IDF master 分支(最新版本)的文档,该版本在持续开发中。还有 `Stable version`_ 的文档,以及其他版本的文档 :doc:`/versions` 供参考。
+     This is documentation for the master branch (latest version) of ESP-IDF. This version is under continual development. `Stable version`_ documentation is available, as well as other :doc:`/versions`.
+"""
+            ,"stable" : """
+.. note::
+     这是ESP-IDF 稳定版本 %s 的文档,还有其他版本的文档 :doc:`/versions` 供参考。
+"""
+            ,"branch" : """
+.. note::
+     这是ESP-IDF %s ``%s`` 版本的文档,还有其他版本的文档 :doc:`/versions` 供参考。
+"""
+            },  # version-note
+    }# zh_CN
+}
+
+
+def main():
+    if len(sys.argv) != 3:
+        print("Usage: gen-git-clone.py <language> <output file path>")
+        sys.exit(1)
+
+    language = sys.argv[1]
+    out_dir = sys.argv[2]
+    if not os.path.exists(out_dir):
+        print("Creating directory %s" % out_dir)
+        os.mkdir(out_dir)
+
+    template = TEMPLATES[language]
+
+    version, ver_type, is_stable = get_version()
+
+    write_git_clone_inc(template["git-clone"], out_dir, version, ver_type, is_stable)
+    write_version_note(template["version-note"], out_dir, version, ver_type, is_stable)
+    print("Done")
+
+
+def write_git_clone_inc(template, out_dir, version, ver_type, is_stable):
+    zipfile = template["zipfile"]
+    if version == "master":
+        args = {
+            "clone_args" : "",
+            "extra_note" : template["master"],
+            "zipfile_note" : zipfile["unstable"]
+        }
+    else:
+        args = {
+            "clone_args" : "-b %s " % version,
+            "extra_note" : template["branch"] % {"clone_arg" : version, "ver_type" : ver_type},
+            "zipfile_note" : zipfile["stable"] if is_stable else zipfile["unstable"]
+        }
+    out_file = os.path.join(out_dir, "git-clone.inc")
+    with open(out_file, "w") as f:
+        f.write(template["template"] % args)
+    print("%s written" % out_file)
+
+
+def write_version_note(template, out_dir, version, ver_type, is_stable):
+    if version == "master":
+        content = template["master"]
+    elif ver_type == "tag" and is_stable:
+        content = template["stable"] % version
+    else:
+        content = template["branch"] % (ver_type, version)
+    out_file = os.path.join(out_dir, "version-note.inc")
+    with open(out_file, "w") as f:
+        f.write(content)
+    print("%s written" % out_file)
+
+
+def get_version():
+    """
+    Returns a tuple of (name of branch/tag, type branch/tag, is_stable)
+    """
+    # Trust what RTD says our version is, if it is set
+    version = os.environ.get("READTHEDOCS_VERSION", None)
+    if version == "latest":
+        return ("master", "branch", False)
+
+    # Otherwise, use git to look for a tag
+    try:
+        tag = subprocess.check_output(["git", "describe", "--tags", "--exact-match"]).strip()
+        is_stable = re.match(r"v[0-9\.]+$", tag) is not None
+        return (tag, "tag", is_stable)
+    except subprocess.CalledProcessError:
+        pass
+
+    # No tag, look for a branch
+    refs = subprocess.check_output(["git", "for-each-ref", "--points-at", "HEAD", "--format", "%(refname)"])
+    print("refs:\n%s" % refs)
+    refs = refs.split("\n")
+    # Note: this looks for branches in 'origin' because GitLab CI doesn't check out a local branch
+    branches = [ r.replace("refs/remotes/origin/","").strip() for r in refs if r.startswith("refs/remotes/origin/") ]
+    if len(branches) == 0:
+        # last resort, return the commit (may happen on Gitlab CI sometimes, unclear why)
+        return (subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]).strip(), "commit", False)
+    if "master" in branches:
+        return ("master", "branch", False)
+    else:
+        return (branches[0], "branch", False)  # take whatever the first branch is
+
+if __name__ == "__main__":
+    main()
index cc32abbd516fa5315b1619751f5b3a49ae5295d6..bf7ce5d14f983570c501676bf0e3c9edd8288c3d 100644 (file)
@@ -1,201 +1,2 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS    =
-SPHINXBUILD   = sphinx-build
-PAPER         =
-BUILDDIR      = _build
-
-# User-friendly check for sphinx-build
-ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
-$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
-endif
-
-# Internal variables.
-PAPEROPT_a4     = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) -w sphinx-warning-log.txt .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
-help:
-       @echo "Please use \`make <target>' where <target> is one of"
-       @echo "  html       to make standalone HTML files"
-       @echo "  dirhtml    to make HTML files named index.html in directories"
-       @echo "  singlehtml to make a single large HTML file"
-       @echo "  pickle     to make pickle files"
-       @echo "  json       to make JSON files"
-       @echo "  htmlhelp   to make HTML files and a HTML help project"
-       @echo "  qthelp     to make HTML files and a qthelp project"
-       @echo "  devhelp    to make HTML files and a Devhelp project"
-       @echo "  epub       to make an epub"
-       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
-       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
-       @echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
-       @echo "  text       to make text files"
-       @echo "  man        to make manual pages"
-       @echo "  texinfo    to make Texinfo files"
-       @echo "  info       to make Texinfo files and run them through makeinfo"
-       @echo "  gettext    to make PO message catalogs"
-       @echo "  changes    to make an overview of all changed/added/deprecated items"
-       @echo "  xml        to make Docutils-native XML files"
-       @echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
-       @echo "  linkcheck  to check all external links for integrity"
-       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
-
-clean:
-       rm -rf $(BUILDDIR)/*
-
-html:
-       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
-       @echo
-       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
-       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
-       @echo
-       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
-       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
-       @echo
-       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
-       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
-       @echo
-       @echo "Build finished; now you can process the pickle files."
-
-json:
-       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
-       @echo
-       @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
-       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
-       @echo
-       @echo "Build finished; now you can run HTML Help Workshop with the" \
-             ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
-       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
-       @echo
-       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
-             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
-       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhcp"
-       @echo "To view the help file:"
-       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhc"
-
-devhelp:
-       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
-       @echo
-       @echo "Build finished."
-       @echo "To view the help file:"
-       @echo "# mkdir -p $$HOME/.local/share/devhelp/ReadtheDocsTemplate"
-       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ReadtheDocsTemplate"
-       @echo "# devhelp"
-
-epub:
-       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
-       @echo
-       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
-       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-       @echo
-       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
-       @echo "Run \`make' in that directory to run these through (pdf)latex" \
-             "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
-       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-       @echo "Running LaTeX files through pdflatex..."
-       $(MAKE) -C $(BUILDDIR)/latex all-pdf
-       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-latexpdfja:
-       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-       @echo "Running LaTeX files through platex and dvipdfmx..."
-       $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
-       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
-       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
-       @echo
-       @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
-       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
-       @echo
-       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
-       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-       @echo
-       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
-       @echo "Run \`make' in that directory to run these through makeinfo" \
-             "(use \`make info' here to do that automatically)."
-
-info:
-       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-       @echo "Running Texinfo files through makeinfo..."
-       make -C $(BUILDDIR)/texinfo info
-       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
-       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
-       @echo
-       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
-       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
-       @echo
-       @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
-       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
-       @echo
-       @echo "Link check complete; look for any errors in the above output " \
-             "or in $(BUILDDIR)/linkcheck/output.txt."
-
-gh-linkcheck:
-       @echo "Checking for hardcoded GitHub links"
-       @if (find ../ -name '*.rst' | xargs grep \
-               'https://github.com/espressif/esp-idf/tree\|https://github.com/espressif/esp-idf/blob\|https://github.com/espressif/esp-idf/raw'\
-               ); \
-       then \
-               echo "WARNINIG: Some .rst files contain hardcoded Github links."; \
-               echo "Please check above output and replace links with one of the following:"; \
-               echo "- :idf:\`dir\` - points to directory inside ESP-IDF"; \
-               echo "- :idf_file:\`file\` - points to file inside ESP-IDF"; \
-               echo "- :idf_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
-               echo "- :component:\`dir\` - points to directory inside ESP-IDF components dir"; \
-               echo "- :component_file:\`file\` - points to file inside ESP-IDF components dir"; \
-               echo "- :component_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
-               echo "  components dir"; \
-               echo "- :example:\`dir\` - points to directory inside ESP-IDF examples dir"; \
-               echo "- :example_file:\`file\` - points to file inside ESP-IDF examples dir"; \
-               echo "- :example_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \
-               echo "  examples dir"; \
-               echo "These link types will point to the correct GitHub version automatically"; \
-               exit 1; \
-       fi
-       @echo "No hardcoded links found"
-
-doctest:
-       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
-       @echo "Testing of doctests in the sources finished, look at the " \
-             "results in $(BUILDDIR)/doctest/output.txt."
-
-xml:
-       $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
-       @echo
-       @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
-
-pseudoxml:
-       $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
-       @echo
-       @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
+LANGUAGE=zh_CN
+include ../docs_common.mk
index d42993f788cdecfca61a98d60c6ba2d882086a85..1e78cd98a7b8e5ce0c1ae06a8c99964b40b6c623 100644 (file)
@@ -1 +1,241 @@
-.. include:: ../../en/api-guides/unit-tests.rst
\ No newline at end of file
+ESP32 中的单元测试
+==================
+
+ESP-IDF
+中附带了一个基于 ``Unity`` 的单元测试应用程序框架,且所有的单元测试用例分别保存在
+ESP-IDF 仓库中每个组件的 ``test`` 子目录中。
+
+添加常规测试用例
+----------------
+
+单元测试被添加在相应组件的 ``test`` 子目录中,测试用例写在 C 文件中,一个
+C 文件可以包含多个测试用例。测试文件的名字要以 “test” 开头。
+
+测试文件需要包含 ``unity.h`` 头文件,此外还需要包含待测试 C
+模块需要的头文件。
+
+测试用例需要通过 C 文件中特定的函数来添加,如下所示:
+
+.. code:: c
+
+   TEST_CASE("test name", "[module name]"
+   {
+           // 在这里添加测试用例
+   }
+
+-  第一个参数是字符串,用来描述当前测试。
+
+-  第二个参数是字符串,用方括号中的标识符来表示,标识符用来对相关测试或具有特定属性的测试进行分组。
+
+没有必要在每个测试用例中使用 ``UNITY_BEGIN()`` 和 ``UNITY_END()``
+来声明主函数的区域, ``unity_platform.c`` 会自动调用
+``UNITY_BEGIN()``\ , 然后运行测试用例,最后调用 ``UNITY_END()``\ 。
+
+每一个测试子目录下都应该包含一个
+``component.mk``\ ,并且里面至少要包含如下的一行内容:
+
+.. code:: makefile
+
+   COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
+
+更多关于如何在 Unity 下编写测试用例的信息,请查阅
+http://www.throwtheswitch.org/unity 。
+
+
+添加多设备测试用例
+------------------
+
+常规测试用例会在一个 DUT(Device Under
+Test,在试设备)上执行,那些需要互相通信的组件(比如
+GPIO,SPI...)不能使用常规测试用例进行测试。多设备测试用例支持使用多个
+DUT 进行写入和运行测试。
+
+以下是一个多设备测试用例:
+
+.. code:: c
+
+   void gpio_master_test()
+   {
+       gpio_config_t slave_config = {
+               .pin_bit_mask = 1 << MASTER_GPIO_PIN,
+               .mode = GPIO_MODE_INPUT,
+       };
+       gpio_config(&slave_config);
+       unity_wait_for_signal("output high level");
+       TEST_ASSERT(gpio_get_level(MASTER_GPIO_PIN) == 1);
+   }
+
+   void gpio_slave_test()
+   {
+       gpio_config_t master_config = {
+               .pin_bit_mask = 1 << SLAVE_GPIO_PIN,
+               .mode = GPIO_MODE_OUTPUT,
+       };
+       gpio_config(&master_config);
+       gpio_set_level(SLAVE_GPIO_PIN, 1);
+       unity_send_signal("output high level");
+   }
+
+   TEST_CASE_MULTIPLE_DEVICES("gpio multiple devices test example", "[driver]", gpio_master_test, gpio_slave_test);
+
+宏 ``TEST_CASE_MULTIPLE_DEVICES`` 用来声明多设备测试用例,
+
+-  第一个参数指定测试用例的名字。
+
+-  第二个参数是测试用例的描述。
+
+-  从第三个参数开始,可以指定最多5个测试函数,每个函数都是单独运行在一个
+   DUT 上的测试入口点。
+
+在不同的 DUT 上运行的测试用例,通常会要求它们之间进行同步。我们提供
+``unity_wait_for_signal`` 和 ``unity_send_signal`` 这两个函数来使用 UART
+去支持同步操作。如上例中的场景,slave 应该在在 master 设置好 GPIO
+电平后再去读取 GPIO 电平,DUT 的 UART
+终端会打印提示信息,并要求用户进行交互。
+
+DUT1(master)终端:
+
+.. code:: bash
+
+   Waiting for signal: [output high level]!
+   Please press "Enter" key once any board send this signal.
+
+DUT2(slave)终端:
+
+.. code:: bash
+
+   Send signal: [output high level]!
+
+一旦 DUT2 发送了该信号,您需要在 DUT2 的终端输入回车,然后 DUT1 会从
+``unity_wait_for_signal`` 函数中解除阻塞,并开始更改 GPIO 的电平。
+
+
+添加多阶段测试用例
+------------------
+
+常规的测试用例无需重启就会结束(或者仅需要检查是否发生了重启),可有些时候我们想在某些特定类型的重启事件后运行指定的测试代码,例如,我们想在深度睡眠唤醒后检查复位的原因是否正确。首先我们需要出发深度睡眠复位事件,然后检查复位的原因。为了实现这一点,我们可以定义多阶段测试用例来将这些测试函数组合在一起。
+
+.. code:: c
+
+   static void trigger_deepsleep(void)
+   {
+       esp_sleep_enable_timer_wakeup(2000);
+       esp_deep_sleep_start();
+   }
+
+   void check_deepsleep_reset_reason()
+   {
+       RESET_REASON reason = rtc_get_reset_reason(0);
+       TEST_ASSERT(reason == DEEPSLEEP_RESET);
+   }
+
+   TEST_CASE_MULTIPLE_STAGES("reset reason check for deepsleep", "[esp32]", trigger_deepsleep, check_deepsleep_reset_reason);
+
+多阶段测试用例向用户呈现了一组测试函数,它需要用户进行交互(选择用例并选择不同的阶段)来运行。
+
+
+编译单元测试程序
+----------------
+
+按照 esp-idf 顶层目录的 README 文件中的说明进行操作,请确保 ``IDF_PATH``
+环境变量已经被设置指向了 esp-idf 的顶层目录。
+
+切换到 ``tools/unit-test-app`` 目录下进行配置和编译:
+
+-  ``make menuconfig`` - 配置单元测试程序。
+
+-  ``make TESTS_ALL=1`` - 编译单元测试程序,测试每个组件 ``test``
+   子目录下的用例。
+
+-  ``make TEST_COMPONENTS='xxx'`` - 编译单元测试程序,测试指定的组件。
+
+-  ``make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='xxx'`` -
+   编译单元测试程序,测试所有(除开指定)的组件。例如
+   ``make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='ulp mbedtls'`` -
+   编译所有的单元测试,不包括 ``ulp`` 和 ``mbedtls``\ 组件。
+
+当编译完成时,它会打印出烧写芯片的指令。您只需要运行 ``make flash``
+即可烧写所有编译输出的文件。
+
+您还可以运行 ``make flash TESTS_ALL=1`` 或者
+``make TEST_COMPONENTS='xxx'``
+来编译并烧写,所有需要的文件都会在烧写之前自动重新编译。
+
+使用 ``menuconfig`` 可以设置烧写测试程序所使用的串口。
+
+
+运行单元测试
+------------
+
+烧写完成后重启 ESP32, 它将启动单元测试程序。
+
+当单元测试应用程序空闲时,输入回车键,它会打印出测试菜单,其中包含所有的测试项目。
+
+.. code:: bash
+
+   Here's the test menu, pick your combo:
+   (1)     "esp_ota_begin() verifies arguments" [ota]
+   (2)     "esp_ota_get_next_update_partition logic" [ota]
+   (3)     "Verify bootloader image in flash" [bootloader_support]
+   (4)     "Verify unit test app image" [bootloader_support]
+   (5)     "can use new and delete" [cxx]
+   (6)     "can call virtual functions" [cxx]
+   (7)     "can use static initializers for non-POD types" [cxx]
+   (8)     "can use std::vector" [cxx]
+   (9)     "static initialization guards work as expected" [cxx]
+   (10)    "global initializers run in the correct order" [cxx]
+   (11)    "before scheduler has started, static initializers work correctly" [cxx]
+   (12)    "adc2 work with wifi" [adc]
+   (13)    "gpio master/slave test example" [ignore][misc][test_env=UT_T2_1][multi_device]
+           (1)     "gpio_master_test"
+           (2)     "gpio_slave_test"
+   (14)    "SPI Master clockdiv calculation routines" [spi]
+   (15)    "SPI Master test" [spi][ignore]
+   (16)    "SPI Master test, interaction of multiple devs" [spi][ignore]
+   (17)    "SPI Master no response when switch from host1 (HSPI) to host2 (VSPI)" [spi]
+   (18)    "SPI Master DMA test, TX and RX in different regions" [spi]
+   (19)    "SPI Master DMA test: length, start, not aligned" [spi]
+   (20)    "reset reason check for deepsleep" [esp32][test_env=UT_T2_1][multi_stage]
+           (1)     "trigger_deepsleep"
+           (2)     "check_deepsleep_reset_reason"
+
+常规测试用例会打印用例名字和描述,主从测试用例还会打印子菜单(已注册的测试函数的名字)。
+
+可以输入以下任意一项来运行测试用例:
+
+-  引号中的测试用例的名字,运行单个测试用例。
+
+-  测试用例的序号,运行单个测试用例。
+
+-  方括号中的模块名字,运行指定模块所有的测试用例。
+
+-  星号,运行所有测试用例。
+
+``[multi_device]`` 和 ``[multi_stage]``
+标签告诉测试运行者该用例是多设备测试还是多阶段测试。这些标签由
+``TEST_CASE_MULTIPLE_STAGES`` 和 ``TEST_CASE_MULTIPLE_DEVICES``
+宏自动生成。
+
+一旦选择了多设备测试用例,它会打印一个子菜单:
+
+.. code:: bash
+
+   Running gpio master/slave test example...
+   gpio master/slave test example
+           (1)     "gpio_master_test"
+           (2)     "gpio_slave_test"
+
+您需要输入数字以选择在 DUT 上运行的测试。
+
+与多设备测试用例相似,多阶段测试用例也会打印子菜单:
+
+.. code:: bash
+
+   Running reset reason check for deepsleep...
+   reset reason check for deepsleep
+           (1)     "trigger_deepsleep"
+           (2)     "check_deepsleep_reset_reason"
+
+第一次执行此用例时,输入 ``1`` 来运行第一阶段(触发深度睡眠)。在重启
+DUT 并再次选择运行此用例后,输入 ``2``
+来运行第二阶段。只有在最后一个阶段通过并且之前所有的阶段都成功触发了复位的情况下,该测试才算通过。
diff --git a/docs/zh_CN/api-reference/system/esp_https_ota.rst b/docs/zh_CN/api-reference/system/esp_https_ota.rst
new file mode 100644 (file)
index 0000000..e831ef9
--- /dev/null
@@ -0,0 +1 @@
+.. include:: ../../../en/api-reference/system/esp_https_ota.rst
index ba7aa5a7b4d2f81ddcb1592ede6141d0c7244482..6e38dbdfceb4b2d792fe4f153a00fce050a6c3dd 100644 (file)
@@ -5,6 +5,8 @@
 
 本文档旨在指导用户创建 ESP32 的软件环境。本文将通过一个简单的例子来说明如何使用 ESP-IDF (Espressif IoT Development Framework),包括配置、编译、下载固件到开发板等步骤。
 
+.. include:: /_build/inc/version-note.inc
+
 概述
 ======
 
@@ -73,7 +75,7 @@ ESP32 是一套 Wi-Fi (2.4 GHz) 和蓝牙 (4.2) 双模解决方案,集成了
     :hidden:
 
     Windows <windows-setup>
-    Linux <linux-setup> 
+    Linux <linux-setup>
     MacOS <macos-setup>
 
 +-------------------+-------------------+-------------------+
@@ -110,12 +112,11 @@ ESP32 是一套 Wi-Fi (2.4 GHz) 和蓝牙 (4.2) 双模解决方案,集成了
 
 .. highlight:: bash
 
-工具链(包括用于编译和构建应用程序的程序)安装完后,你还需要 ESP32 相关的 API/库。API/库在 `ESP-IDF 仓库 <https://github.com/espressif/esp-idf>`_ 中。要获取这些 API/库,打开一个终端,进入某个你希望存放 ESP-IDF 的目录,然后 ``git clone`` 以下指令: ::
+工具链(包括用于编译和构建应用程序的程序)安装完后,你还需要 ESP32 相关的 API/库。API/库在 `ESP-IDF 仓库 <https://github.com/espressif/esp-idf>`_ 中。
 
-    cd ~/esp
-    git clone --recursive https://github.com/espressif/esp-idf.git
+.. include:: /_build/inc/git-clone.inc
 
-ESP-IDF 将会被下载到 ``~/esp/esp-idf``
+查看 :doc:/versions 以获取不同情况下选择要使用的分支的帮助
 
 .. note::
 
@@ -176,7 +177,7 @@ ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照
     :figclass: align-center
 
     工程配置 - 主窗口
-    
+
 在菜单中,进入 ``Serial flasher config`` > ``Default serial port`` 配置串口(工程将会加载到该串口上)。输入回车确认选择,选择 ``< Save >`` 保存配置,然后选择 ``< Exit >`` 退出应用程序。
 
 .. note::
@@ -285,31 +286,17 @@ ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照
 
 你已完成 ESP32 的入门!
 
-现在你可以尝试其他的示例工程 :idf:`examples`,或者直接开发自己的应用程序。 
+现在你可以尝试其他的示例工程 :idf:`examples`,或者直接开发自己的应用程序。
 
 更新 ESP-IDF
 =============
 
 使用 ESP-IDF 一段时间后,你可能想要进行升级来获得新的性能或者对 bug 进行修复。最简单的更新方式是删除已有的 ``esp-idf`` 文件夹然后再克隆一个,即重复 :ref:`get-started-get-esp-idf` 里的操作。
 
-另外一种方法是只更新有改动的部分,如果你不容易登陆 GitHub,那么这种方法比较合适。执行以下命令: ::
-
-    cd ~/esp/esp-idf
-    git pull
-    git submodule update --init --recursive
-
-``git pull`` 指令是从 ESP-IDF 仓库中获取合并更新。``git submodule update --init --recursive`` 用来更新现有的子模块或拷贝新的子模块。在 GitHub 上,子模块链接到其他仓库,所以需要这个额外的指令来下载到你的电脑里。
-
-如果你想使用某一版本的 ESP-IDF,比如 `v2.1` 版本,请执行以下指令: ::
-
-    cd ~/esp
-    git clone https://github.com/espressif/esp-idf.git esp-idf-v2.1
-    cd esp-idf-v2.1/
-    git checkout v2.1
-    git submodule update --init --recursive
-
 然后 :doc:`add-idf_path-to-profile`,这样工具链脚本就能够知道这一版本的 ESP-IDF 的具体位置。
 
+另外一种方法是只更新有改动的部分。:ref:`更新步骤取决于现在用的ESP-IDF版本 <updating>`。
+
 
 相关文档
 =================
@@ -323,3 +310,6 @@ ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照
     eclipse-setup
     idf-monitor
     toolchain-setup-scratch
+
+.. _Stable version: https://docs.espressif.com/projects/esp-idf/zh_CN/stable/
+.. _Releases page: https://github.com/espressif/esp-idf/releases
index 9945da9bc5f677ac41c6bb34c8c28d3087f10e6e..4b8afb435e67fb7505ce9d02b3327044397f7ebe 100644 (file)
@@ -44,6 +44,7 @@ ESP-IDF 编程指南
    H/W 参考 <hw-reference/index>
    API 指南 <api-guides/index>
    贡献代码 <contribute/index>
+   版本 <versions>
    相关资源 <resources>
    版权 <COPYRIGHT>
    关于 <about>
diff --git a/docs/zh_CN/versions.rst b/docs/zh_CN/versions.rst
new file mode 100644 (file)
index 0000000..e060a86
--- /dev/null
@@ -0,0 +1 @@
+.. include:: ../en/versions.rst
index b57e4249c21f4d9e2d3ba2ad4bb560d93080febb..69e489930566cf6d137437ea32410b52e0b61a45 100644 (file)
@@ -636,7 +636,7 @@ void app_main()
 
     // Initialize NVS.
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
@@ -703,4 +703,4 @@ void app_main()
     bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
     //gatt server init
     ble_gatts_init();
-}
\ No newline at end of file
+}
index e4881b34002a4b4e78ed108857380de274ff5114..045672125bcf654f6fe0c48ec426315567a826d6 100644 (file)
@@ -46,7 +46,7 @@ void app_main()
 {
     /* Initialize NVS — it is used to store PHY calibration data */
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 602dc01d8ee771fd447f862ebf3a20b04cc7a625..3da55895f011146d20b895c4165cb74fa44dcf30 100644 (file)
@@ -100,7 +100,7 @@ void app_main()
 {
     // Initialize NVS.
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 246d87b3047f5dae268cafc8fc850a87c3d05219..0a67c32468f7fc35e8b10fd2fc8e0fa3b8a69b9d 100644 (file)
@@ -214,7 +214,7 @@ void app_main()
 {
     /* Initialize NVS — it is used to store PHY calibration data */
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 5efc1fb90b6a6b4254d808320c02c2eee9e29047..3094f6bc7fe4a314fc8df1e8b5adc06332a3afe8 100644 (file)
@@ -185,17 +185,18 @@ static void hidd_event_callback(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *
         case ESP_HIDD_EVENT_DEINIT_FINISH:
             break;
                case ESP_HIDD_EVENT_BLE_CONNECT: {
+            ESP_LOGI(HID_DEMO_TAG, "ESP_HIDD_EVENT_BLE_CONNECT");
             hid_conn_id = param->connect.conn_id;
             break;
         }
         case ESP_HIDD_EVENT_BLE_DISCONNECT: {
             sec_conn = false;
-            ESP_LOGE(HID_DEMO_TAG, "%s(), ESP_HIDD_EVENT_BLE_DISCONNECT", __func__);
+            ESP_LOGI(HID_DEMO_TAG, "ESP_HIDD_EVENT_BLE_DISCONNECT");
             esp_ble_gap_start_advertising(&hidd_adv_params);
             break;
         }
         case ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT: {
-            ESP_LOGE(HID_DEMO_TAG, "%s, ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT", __func__);
+            ESP_LOGI(HID_DEMO_TAG, "%s, ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT", __func__);
             ESP_LOG_BUFFER_HEX(HID_DEMO_TAG, param->vendor_write.data, param->vendor_write.length);
         }    
         default:
@@ -218,7 +219,16 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
         break;
      case ESP_GAP_BLE_AUTH_CMPL_EVT:
         sec_conn = true;
-        ESP_LOGE(HID_DEMO_TAG, "staus =%s, ESP_GAP_BLE_AUTH_CMPL_EVT",param->ble_security.auth_cmpl.success ? "success" : "fail");
+        esp_bd_addr_t bd_addr;
+        memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t));
+        ESP_LOGI(HID_DEMO_TAG, "remote BD_ADDR: %08x%04x",\
+                (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+                (bd_addr[4] << 8) + bd_addr[5]);
+        ESP_LOGI(HID_DEMO_TAG, "address type = %d", param->ble_security.auth_cmpl.addr_type);
+        ESP_LOGI(HID_DEMO_TAG, "pair status = %s",param->ble_security.auth_cmpl.success ? "success" : "fail");
+        if(!param->ble_security.auth_cmpl.success) {
+            ESP_LOGE(HID_DEMO_TAG, "fail reason = 0x%x",param->ble_security.auth_cmpl.fail_reason);
+        }
         break;
     default:
         break;
@@ -231,7 +241,7 @@ void hid_demo_task(void *pvParameters)
     while(1) {
         vTaskDelay(2000 / portTICK_PERIOD_MS);
         if (sec_conn) {
-            ESP_LOGE(HID_DEMO_TAG, "Send the volume");
+            ESP_LOGI(HID_DEMO_TAG, "Send the volume");
             send_volum_up = true;
             //uint8_t key_vaule = {HID_KEY_A};
             //esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule, 1);
@@ -241,6 +251,8 @@ void hid_demo_task(void *pvParameters)
                 send_volum_up = false;
                 esp_hidd_send_consumer_value(hid_conn_id, HID_CONSUMER_VOLUME_UP, false);
                 esp_hidd_send_consumer_value(hid_conn_id, HID_CONSUMER_VOLUME_DOWN, true);
+                vTaskDelay(3000 / portTICK_PERIOD_MS);
+                esp_hidd_send_consumer_value(hid_conn_id, HID_CONSUMER_VOLUME_DOWN, false);
             }
         }
     }
@@ -253,7 +265,7 @@ void app_main()
 
     // Initialize NVS.
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index ec7e84562da5bfbfbd0351f44f9c8a2de56ecc5c..8d112fad875928e162a19ceb03015c2058935998 100644 (file)
@@ -196,6 +196,15 @@ enum
 
 #define HI_UINT16(a) (((a) >> 8) & 0xFF)
 #define LO_UINT16(a) ((a) & 0xFF)
+#define PROFILE_NUM            1
+#define PROFILE_APP_IDX        0
+
+struct gatts_profile_inst {
+    esp_gatts_cb_t gatts_cb;
+    uint16_t gatts_if;
+    uint16_t app_id;
+    uint16_t conn_id;
+};
 
 hidd_le_env_t hidd_le_env;
 
@@ -555,11 +564,11 @@ void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
             break;
         case ESP_GATTS_CONNECT_EVT: {
             esp_hidd_cb_param_t cb_param = {0};
-                       ESP_LOGE(HID_LE_PRF_TAG, "the connection establish, conn_id = %x",param->connect.conn_id);
+                       ESP_LOGI(HID_LE_PRF_TAG, "HID connection establish, conn_id = %x",param->connect.conn_id);
                        memcpy(cb_param.connect.remote_bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
             cb_param.connect.conn_id = param->connect.conn_id;
             hidd_clcb_alloc(param->connect.conn_id, param->connect.remote_bda);
-            //esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_NO_MITM);
+            esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_NO_MITM);
             if(hidd_le_env.hidd_cb != NULL) {
                 (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_CONNECT, &cb_param);
             }
@@ -592,7 +601,7 @@ void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
                 param->add_attr_tab.status == ESP_GATT_OK) {
                 incl_svc.start_hdl = param->add_attr_tab.handles[BAS_IDX_SVC];
                 incl_svc.end_hdl = incl_svc.start_hdl + BAS_IDX_NB -1;
-                ESP_LOGE(HID_LE_PRF_TAG, "%s(), start added the hid service to the stack database. incl_handle = %d",
+                ESP_LOGI(HID_LE_PRF_TAG, "%s(), start added the hid service to the stack database. incl_handle = %d",
                            __func__, incl_svc.start_hdl);
                 esp_ble_gatts_create_attr_tab(hidd_le_gatt_db, gatts_if, HIDD_LE_IDX_NB, 0);
             }
@@ -600,7 +609,7 @@ void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
                 param->add_attr_tab.status == ESP_GATT_OK) {
                 memcpy(hidd_le_env.hidd_inst.att_tbl, param->add_attr_tab.handles,
                             HIDD_LE_IDX_NB*sizeof(uint16_t));
-                ESP_LOGE(HID_LE_PRF_TAG, "hid svc handle = %x",hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_SVC]);
+                ESP_LOGI(HID_LE_PRF_TAG, "hid svc handle = %x",hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_SVC]);
                 hid_add_id_tbl();
                        esp_ble_gatts_start_service(hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_SVC]);
             } else {
@@ -659,10 +668,47 @@ bool hidd_clcb_dealloc (uint16_t conn_id)
     return false;
 }
 
+static struct gatts_profile_inst heart_rate_profile_tab[PROFILE_NUM] = {
+    [PROFILE_APP_IDX] = {
+        .gatts_cb = esp_hidd_prf_cb_hdl,
+        .gatts_if = ESP_GATT_IF_NONE,       /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
+    },
+
+};
+
+static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
+                                esp_ble_gatts_cb_param_t *param)
+{
+    /* If event is register event, store the gatts_if for each profile */
+    if (event == ESP_GATTS_REG_EVT) {
+        if (param->reg.status == ESP_GATT_OK) {
+            heart_rate_profile_tab[PROFILE_APP_IDX].gatts_if = gatts_if;
+        } else {
+            ESP_LOGI(HID_LE_PRF_TAG, "Reg app failed, app_id %04x, status %d\n",
+                    param->reg.app_id,
+                    param->reg.status);
+            return;
+        }
+    }
+
+    do {
+        int idx;
+        for (idx = 0; idx < PROFILE_NUM; idx++) {
+            if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
+                    gatts_if == heart_rate_profile_tab[idx].gatts_if) {
+                if (heart_rate_profile_tab[idx].gatts_cb) {
+                    heart_rate_profile_tab[idx].gatts_cb(event, gatts_if, param);
+                }
+            }
+        }
+    } while (0);
+}
+
+
 esp_err_t hidd_register_cb(void)
 {
        esp_err_t status;
-       status = esp_ble_gatts_register_callback(esp_hidd_prf_cb_hdl);
+       status = esp_ble_gatts_register_callback(gatts_event_handler);
        return status;
 }
 
index 2da39c5fe8f13d56e0e26ee725fe84073781b0ab..999b047e7803b6419350e7170134932b3f07b01f 100644 (file)
@@ -655,7 +655,7 @@ void app_main()
 
     // Initialize NVS
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index fefb1236bec3cbd4bf0ce4bbf0fff0315767450d..56362cac62ee0afe333cb7f1bf9e07fe062b5887 100644 (file)
@@ -519,7 +519,7 @@ void app_main()
 {
     // Initialize NVS.
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index a1a416b06f2a2ed59b7973f4c864649279793ede..0b245ac676bf24faf1b20e22692575dbc8e06745 100644 (file)
@@ -641,7 +641,7 @@ void app_main()
 
     // Initialize NVS.
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 2ad02c198b69581d0c96c6c24ddee582cd608a30..bb046306e836ab4cb474d1be5867f7123d792937 100644 (file)
@@ -381,7 +381,7 @@ void app_main()
 
     // Initialize NVS
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 65671144392e1e01db3c293527b51dc2aa4c2c5c..ef2b11ef53ccbec9fd63ffd4fb26239c84615257 100644 (file)
@@ -273,7 +273,7 @@ void app_main()
 {
     /* Initialize NVS — it is used to store PHY calibration data */
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 84a8ed48633342d8bad69647b0a8e4e950640a8c..df72951052700e841538c5ea8756aeb2ee3ade37 100644 (file)
@@ -138,7 +138,7 @@ void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
 void app_main()
 {
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index d8b00ebec30c9c8305bc05bd472d18b61031a9ca..ad42c9956b218c47c703e06e777d335ef43bf01d 100644 (file)
@@ -223,7 +223,7 @@ void app_main()
     }
 
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 72a354eb0e84a0fe855e3ba4f992e84d63bab5f9..51c23c094e514ee694b5a3b6a1c575d9a4bc01ab 100644 (file)
@@ -140,7 +140,7 @@ void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
 void app_main()
 {
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 218ff34373799afa37227b9c54e23d7d2b4a819a..f5ef880a7ba887ff6e2489ebccb2bc6f62863705 100644 (file)
@@ -208,7 +208,7 @@ void app_main()
     }
 
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 006a951b3918700d654cab6e7322997999ca07fe..0eb7ef77812bf1599e24d07948e082d4f3636bfa 100644 (file)
@@ -37,7 +37,7 @@ void app_main()
 
     /* Initialize NVS — it is used to store PHY calibration data */
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 1f2cc20e41dfc1b612fc59f7d381f4d7f3674200..e86841ae795864704913453fcf408720bce8f986 100644 (file)
@@ -135,7 +135,7 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
         break;
     case ESP_GATTC_SEARCH_RES_EVT: {
         ESP_LOGI(GATTC_TAG, "SEARCH RES: conn_id = %x is primary service %d", p_data->search_res.conn_id, p_data->search_res.is_primary);
-        ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.start_handle, p_data->search_res.srvc_id.inst_id);
+        ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.end_handle, p_data->search_res.srvc_id.inst_id);
         if (p_data->search_res.srvc_id.uuid.len == ESP_UUID_LEN_16 && p_data->search_res.srvc_id.uuid.uuid.uuid16 == REMOTE_SERVICE_UUID) {
             ESP_LOGI(GATTC_TAG, "service found");
             get_server = true;
@@ -414,7 +414,7 @@ void app_main()
 {
     // Initialize NVS.
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 49725751d13f33efa793bcae88953ec34d854afd..2ed2c86b5e5fa3386fff40cc108a0a876c0467cb 100644 (file)
@@ -41,7 +41,7 @@ void app_main()
 {
     // Initialize NVS.
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
@@ -103,7 +103,7 @@ The main function starts by initializing the non-volatile storage library. This
 
 ```c
 esp_err_t ret = nvs_flash_init();
-if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
     ESP_ERROR_CHECK(nvs_flash_erase());
     ret = nvs_flash_init();
 }
index 71c2a415ac6cd17581f8f43022d2dacb6f019805..8ca47adf702d75255771569995692ae2c4edc809 100644 (file)
@@ -159,7 +159,7 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
         break;
     case ESP_GATTC_SEARCH_RES_EVT: {
         ESP_LOGI(GATTC_TAG, "SEARCH RES: conn_id = %x is primary service %d", p_data->search_res.conn_id, p_data->search_res.is_primary);
-        ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.start_handle, p_data->search_res.srvc_id.inst_id);
+        ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.end_handle, p_data->search_res.srvc_id.inst_id);
         if (p_data->search_res.srvc_id.uuid.len == ESP_UUID_LEN_16 && p_data->search_res.srvc_id.uuid.uuid.uuid16 == REMOTE_SERVICE_UUID) {
             ESP_LOGI(GATTC_TAG, "UUID16: %x", p_data->search_res.srvc_id.uuid.uuid.uuid16);
             get_service = true;
@@ -460,7 +460,7 @@ void app_main()
 {
     // Initialize NVS.
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index de4376d743f5e4fb81323889bd6664ca56eb3807..d7aec7a21ad0da3ad9bdb4b1489b47e98923a1f3 100644 (file)
@@ -320,6 +320,9 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
                 (bd_addr[4] << 8) + bd_addr[5]);
         ESP_LOGI(GATTS_TABLE_TAG, "address type = %d", param->ble_security.auth_cmpl.addr_type);
         ESP_LOGI(GATTS_TABLE_TAG, "pair status = %s",param->ble_security.auth_cmpl.success ? "success" : "fail");
+        if(!param->ble_security.auth_cmpl.success) {
+            ESP_LOGI(GATTS_TABLE_TAG, "fail reason = 0x%x",param->ble_security.auth_cmpl.fail_reason);
+        }
         show_bonded_devices();
         break;
     }
@@ -466,7 +469,7 @@ void app_main()
 
     // Initialize NVS.
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 76dc104a2b117dceffd9d7a59c297b4e77272d3e..57f17b1dd26d8726c02cbb88e4666240c9cfa78a 100644 (file)
@@ -679,7 +679,7 @@ void app_main()
 
     // Initialize NVS.
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 34a44d415c1f64efccf7fd5800dbbfea8f61f189..495a2bde8f06868c536bb7ffbe72b40e1602a3f5 100644 (file)
@@ -44,7 +44,7 @@ The entry point to this example is the app_main() function:
 
     // Initialize NVS.
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index cc62e5013e53d81dabb2ba47cea3b9b6a198798f..704e735b904c24c654ac3a95cf923f5c2ead4363 100644 (file)
@@ -517,7 +517,7 @@ void app_main()
 
     /* Initialize NVS. */
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index a317dc8da27eab9ff2222285984f6534f97b3fa3..c86d82cc2c9fb11a05608e4989cf45be8f06a5ec 100644 (file)
@@ -81,7 +81,7 @@ void app_main()
 
     // Initialize NVS.
     ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 71f70d4701819b40356b2b41bfaac5bd65dd2a24..b6499a766840a0a2469e11828f6f3e0bb4b0d0f0 100644 (file)
@@ -178,7 +178,7 @@ static void gattc_profile_a_event_handler(esp_gattc_cb_event_t event, esp_gatt_i
         break;
     case ESP_GATTC_SEARCH_RES_EVT: {
         ESP_LOGI(GATTC_TAG, "SEARCH RES: conn_id = %x is primary service %d", p_data->search_res.conn_id, p_data->search_res.is_primary);
-        ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.start_handle, p_data->search_res.srvc_id.inst_id);
+        ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.end_handle, p_data->search_res.srvc_id.inst_id);
         if (p_data->search_res.srvc_id.uuid.len == ESP_UUID_LEN_16 && p_data->search_res.srvc_id.uuid.uuid.uuid16 == REMOTE_SERVICE_UUID) {
             ESP_LOGI(GATTC_TAG, "UUID16: %x", p_data->search_res.srvc_id.uuid.uuid.uuid16);
             get_service_a = true;
@@ -378,7 +378,7 @@ static void gattc_profile_b_event_handler(esp_gattc_cb_event_t event, esp_gatt_i
         break;
     case ESP_GATTC_SEARCH_RES_EVT: {
         ESP_LOGI(GATTC_TAG, "SEARCH RES: conn_id = %x is primary service %d", p_data->search_res.conn_id, p_data->search_res.is_primary);
-        ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.start_handle, p_data->search_res.srvc_id.inst_id);
+        ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.end_handle, p_data->search_res.srvc_id.inst_id);
         if (p_data->search_res.srvc_id.uuid.len == ESP_UUID_LEN_16 && p_data->search_res.srvc_id.uuid.uuid.uuid16 == REMOTE_SERVICE_UUID) {
             ESP_LOGI(GATTC_TAG, "UUID16: %x", p_data->search_res.srvc_id.uuid.uuid.uuid16);
             get_service_b = true;
@@ -577,7 +577,7 @@ static void gattc_profile_c_event_handler(esp_gattc_cb_event_t event, esp_gatt_i
         break;
     case ESP_GATTC_SEARCH_RES_EVT: {
         ESP_LOGI(GATTC_TAG, "SEARCH RES: conn_id = %x is primary service %d", p_data->search_res.conn_id, p_data->search_res.is_primary);
-        ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.start_handle, p_data->search_res.srvc_id.inst_id);
+        ESP_LOGI(GATTC_TAG, "start handle %d end handle %d current handle value %d", p_data->search_res.start_handle, p_data->search_res.end_handle, p_data->search_res.srvc_id.inst_id);
         if (p_data->search_res.srvc_id.uuid.len == ESP_UUID_LEN_16 && p_data->search_res.srvc_id.uuid.uuid.uuid16 == REMOTE_SERVICE_UUID) {
             ESP_LOGI(GATTC_TAG, "UUID16: %x", p_data->search_res.srvc_id.uuid.uuid.uuid16);
             get_service_c = true;
@@ -886,7 +886,7 @@ static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp
 void app_main()
 {
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index a1cce97c5aba23c1b37c4e7fc227289066bdc260..f38c3f67327dafa9fd435eca948e0a6e99b1d507 100644 (file)
@@ -34,10 +34,12 @@ def chat_server_sketch(my_ip):
     print("Starting the server on {}".format(my_ip))
     port=2222
     s=socket(AF_INET, SOCK_STREAM)
+    s.settimeout(600)
     s.bind((my_ip, port))
     s.listen(1)
     q,addr=s.accept()
     print("connection accepted")
+    q.settimeout(30)
     q.send(g_msg_to_client)
     data = q.recv(1024)
     # check if received initial empty message
@@ -75,7 +77,7 @@ def test_examples_protocol_asio_chat_client(env, extra_data):
     thread1.start()
     # 2. start the dut test and wait till client gets IP address
     dut1.start_app()
-    data = dut1.expect(re.compile(r" sta ip: ([^,]+),"))
+    data = dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30)
     # 3. send host's IP to the client i.e. the `dut1`
     dut1.write(host_ip)
     # 4. client `dut1` should receive a message
@@ -86,7 +88,7 @@ def test_examples_protocol_asio_chat_client(env, extra_data):
         time.sleep(1)
     print(g_client_response)
     # 6. evaluate host_server received this message
-    if (g_client_response[4:] == test_msg):
+    if (g_client_response[4:7] == test_msg):
         print("PASS: Received correct message")
         pass
     else:
index 55746f1f97b59b2ef12ddb19c8657ddf97bd2fe1..9f3e1408b5db1bbf1b07e73720dfea6ede5dcb75 100644 (file)
@@ -37,9 +37,10 @@ def test_examples_protocol_asio_chat_server(env, extra_data):
     # 1. start test
     dut1.start_app()
     # 2. get the server IP address
-    data = dut1.expect(re.compile(r" sta ip: ([^,]+),"))
+    data = dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30)
     # 3. create tcp client and connect to server
     cli = socket(AF_INET,SOCK_STREAM)
+    cli.settimeout(30)
     cli.connect((data[0],80))
     cli.send(test_msg)
     data = cli.recv(1024)
index 1ab432e62677ca32c5f545bf8c52753eaffce62f..3514bbc2c20204b6f854b5420a0fe94195534f30 100644 (file)
@@ -38,9 +38,10 @@ def test_examples_protocol_asio_tcp_server(env, extra_data):
     # 1. start test
     dut1.start_app()
     # 2. get the server IP address
-    data = dut1.expect(re.compile(r" sta ip: ([^,]+),"))
+    data = dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30)
     # 3. create tcp client and connect to server
     cli = socket(AF_INET,SOCK_STREAM)
+    cli.settimeout(30)
     cli.connect((data[0],80))
     cli.send(test_msg)
     data = cli.recv(1024)
index 490a8007a854a0f46324d74723afff1e2aa5b7f5..7b20b95ca128c06cf44509af44c62f0bf6eb26f0 100644 (file)
@@ -38,9 +38,10 @@ def test_examples_protocol_asio_udp_server(env, extra_data):
     # 1. start test
     dut1.start_app()
     # 2. get the server IP address
-    data = dut1.expect(re.compile(r" sta ip: ([^,]+),"))
+    data = dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30)
     # 3. create tcp client and connect to server
     cli = socket(AF_INET, SOCK_DGRAM)
+    cli.settimeout(30)
     cli.connect((data[0], 80))
     cli.send(test_msg)
     data = cli.recv(1024)
index d4e22bd1ecd28319c2370d60a85f0e722b11a03b..c5b48ae8e72dabd675f73ef49736f272b20a4738 100644 (file)
@@ -321,7 +321,7 @@ void app_main()
 {
     // Initialize NVS.
     esp_err_t err = nvs_flash_init();
-    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         err = nvs_flash_init();
     }
index 2b489d57be7c031cc01a1f3e88a9600d4c9eb792..82ef783585b3d4309f9f0ab0a390cddb0667c329 100644 (file)
@@ -200,12 +200,14 @@ void aws_iot_task(void *param) {
     windowActuator.pData = &windowOpen;
     windowActuator.pKey = "windowOpen";
     windowActuator.type = SHADOW_JSON_BOOL;
+    windowActuator.dataLength = sizeof(bool);
 
     jsonStruct_t temperatureHandler;
     temperatureHandler.cb = NULL;
     temperatureHandler.pKey = "temperature";
     temperatureHandler.pData = &temperature;
     temperatureHandler.type = SHADOW_JSON_FLOAT;
+    temperatureHandler.dataLength = sizeof(float);
 
     ESP_LOGI(TAG, "AWS IoT SDK Version %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
 
@@ -356,7 +358,7 @@ static void initialise_wifi(void)
 void app_main()
 {
     esp_err_t err = nvs_flash_init();
-    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         err = nvs_flash_init();
     }
index 9ca1d6f09103869792461ec57883c664f7ba8f99..063510a80542ada09c11161dc717b4dfe6a65d61 100644 (file)
@@ -35,6 +35,7 @@ def test_examples_protocol_esp_http_client(env, extra_data):
     dut1.expect(re.compile(r"HTTP PUT Status = 200, content_length = (\d)"))
     dut1.expect(re.compile(r"HTTP PATCH Status = 200, content_length = (\d)"))
     dut1.expect(re.compile(r"HTTP DELETE Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP HEAD Status = 200, content_length = (\d)"))
     dut1.expect(re.compile(r"HTTP Basic Auth Status = 200, content_length = (\d)"))
     dut1.expect(re.compile(r"HTTP Basic Auth redirect Status = 200, content_length = (\d)"))
     dut1.expect(re.compile(r"HTTP Digest Auth Status = 200, content_length = (\d)"))
index 4a489080b9190a62197816f0a9bcc4066c5ce8fc..f862ddc7002fa279c237549f1d1e304a91f00abd 100644 (file)
@@ -136,6 +136,18 @@ static void http_rest()
         ESP_LOGE(TAG, "HTTP DELETE request failed: %s", esp_err_to_name(err));
     }
 
+    //HEAD
+    esp_http_client_set_url(client, "http://httpbin.org/get");
+    esp_http_client_set_method(client, HTTP_METHOD_HEAD);
+    err = esp_http_client_perform(client);
+    if (err == ESP_OK) {
+        ESP_LOGI(TAG, "HTTP HEAD Status = %d, content_length = %d",
+                esp_http_client_get_status_code(client),
+                esp_http_client_get_content_length(client));
+    } else {
+        ESP_LOGE(TAG, "HTTP HEAD request failed: %s", esp_err_to_name(err));
+    }
+
     esp_http_client_cleanup(client);
 }
 
@@ -351,7 +363,7 @@ static void http_test_task(void *pvParameters)
 void app_main()
 {
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
       ESP_ERROR_CHECK(nvs_flash_erase());
       ret = nvs_flash_init();
     }
index 7725294d4287dc3f7b66446ad29d05d9d656a97d..cdcc6ec977f2717b9f1e7d14d5230ed4517ddc59 100644 (file)
@@ -145,6 +145,7 @@ static void http2_task(void *args)
     }
 
     sh2lib_free(&hd);
+    vTaskDelete(NULL);
 }
 
 static esp_err_t event_handler(void *ctx, system_event_t *event)
index 8c11e72fd085d20ada664e87fdf7155efb1c8a58..e5bd6eabe5a7ef5e88f1616e3b16a2580d1d1256 100644 (file)
@@ -147,7 +147,7 @@ esp_err_t print_what_saved(void)
 void app_main()
 {
     esp_err_t err = nvs_flash_init();
-    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         // NVS partition was truncated and needs to be erased
         // Retry nvs_flash_init
         ESP_ERROR_CHECK(nvs_flash_erase());
index c4aa598ae1e7b5b013c609186d25658897f213f4..cd03269f0da453b5f9028431b4fe2e112387e323 100644 (file)
@@ -20,7 +20,7 @@ void app_main()
 {
     // Initialize NVS
     esp_err_t err = nvs_flash_init();
-    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         // NVS partition was truncated and needs to be erased
         // Retry nvs_flash_init
         ESP_ERROR_CHECK(nvs_flash_erase());
index 0c7e566abe0b9ed86ca39abc7e8b905106c2e9bc..a115c6f9998eea7a937ddbde12fabd49c7495722 100644 (file)
@@ -50,7 +50,7 @@ static void initialize_filesystem()
 static void initialize_nvs()
 {
     esp_err_t err = nvs_flash_init();
-    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK( nvs_flash_erase() );
         err = nvs_flash_init();
     }
index 316789dbcc86e2785c24a305c9e785fcf65761f9..2d1f42d4b46518cdd519f7a3a7c856107055cc89 100644 (file)
@@ -1,67 +1,94 @@
+# OTA Demo
 
-# Simple OTA Demo
+## Introduction
 
-This example demonstrates a working OTA (over the air) firmware update workflow.
+Over The Air (OTA) updates can be performed in esp32 in two ways:
 
-This example is a *simplified demonstration*, for production firmware updates you should use a secure protocol such as HTTPS.
+- Using native APIs which are part of OTA component.
+- Using simplified APIs which are part of `esp_https_ota`, it's an abstraction layer over OTA APIs to perform updates using HTTPS.
+
+Both these methods are demonstrated in OTA Demo under `native_ota_example` and `simple_ota_example` respectively.
+
+*Note: This guide is common for both the examples*
 
 ---
 
-# Aim
+## Aim
 
 An app running on ESP32 can upgrade itself by downloading a new app "image" binary file, and storing it in flash.
 
 In this example, the ESP32 has 3 images in flash: factory, OTA_0, OTA_1. Each of these is a self-contained partition. The number of OTA image partition is determined by the partition table layout.
 
-Flashing the example over serial with "make flash" updates the factory app image. On first boot, the bootloader loads this factory app image which then performs an OTA update (triggered in the example code). The update downloads a new image from an http server and saves it into the OTA_0 partition. At this point the example code updates the ota_data partition to indicate the new app partition, and resets. The bootloader reads ota_data, determines the new OTA image has been selected, and runs it.
+Flashing the example over serial with "make flash" updates the factory app image. On first boot, the bootloader loads this factory app image which then performs an OTA update (triggered in the example code). The update downloads a new image from a HTTPS server and saves it into the OTA_0 partition. At this point the example code updates the ota_data partition to indicate the new app partition, and resets. The bootloader reads ota_data, determines the new OTA image has been selected, and runs it.
 
 
-# Workflow
+## Workflow
 
 The OTA_workflow.png diagram demonstrates the overall workflow:
 
 ![OTA Workflow diagram](OTA_workflow.png)
 
-## Step 1: Connect to AP
+### Step 1: Connect to AP
 
 Connect your host PC to the same AP that you will use for the ESP32.
 
-## Step 2: Run HTTP Server
-
-Python has a built-in HTTP server that can be used for example purposes.
+### Step 2: Run HTTPS Server
 
 For our upgrade example OTA file, we're going to use the `get-started/hello_world` example.
 
 Open a new terminal to run the HTTP server, then run these commands to build the example and start the server:
 
+Build the example:
+
 ```
 cd $IDF_PATH/examples/get-started/hello_world
 make
 cd build
-python -m SimpleHTTPServer 8070
 ```
 
-While the server is running, the contents of the build directory can be browsed at http://localhost:8070/
+Generate self-signed certificate and key:
+
+*NOTE: `Common Name` of server certificate should be host-name of your server.*
+
+```
+openssl req -x509 -newkey rsa:2048 -keyout ca_key.pem -out ca_cert.pem -days 365
+
+```
+
+Copy the certificate to OTA example directory:
+
+```
+cp ca_cert.pem $IDF_PATH/examples/system/ota/server_certs/ca_cert.pem
+```
 
-NB: On some systems, the command may be `python2 -m SimpleHTTPServer`.
+
+Start the HTTPS server:
+
+```
+openssl s_server -WWW -key ca_key.pem -cert ca_cert.pem -port 8070
+```
 
 NB: You've probably noticed there is nothing special about the "hello world" example when used for OTA updates. This is because any .bin app file which is built by esp-idf can be used as an app image for OTA. The only difference is whether it is written to a factory partition or an OTA partition.
 
 If you have any firewall software running that will block incoming access to port 8070, configure it to allow access while running the example.
 
-## Step 3: Build OTA Example
+### Step 3: Build OTA Example
 
 Change back to the OTA example directory, and type `make menuconfig` to configure the OTA example. Under the "Example Configuration" submenu, fill in the following details:
 
 * WiFi SSID & Password
-* IP address of your host PC as "HTTP Server"
-* HTTP Port number (if using the Python HTTP server above, the default is correct)
+* Firmware Upgrade URL. The URL will be look like this:
+
+```
+https://<host-ip-address>:<host-port>/<firmware-image-filename>
 
-If serving the "hello world" example, you can leave the default filename as-is.
+for e.g,
+https://192.168.0.3:8070/hello-world.bin
+```
 
 Save your changes, and type `make` to build the example.
 
-## Step 4: Flash OTA Example
+### Step 4: Flash OTA Example
 
 When flashing, use the `make flash` to flash the factory image. This command will find if partition table has ota_data partition (as in our case) then ota_data will erase to initial. 
 It allows to run the newly loaded app from a factory partition.
@@ -73,31 +100,29 @@ make flash
 After first update, if you want to return back to factory app (or the first OTA partition, if factory partition is not present) then use the command `make erase_ota`. 
 It erases ota_data partition to initial.
 
-## Step 5: Run the OTA Example
+### Step 5: Run the OTA Example
 
-When the example starts up, it will print "ota: Starting OTA example..." then:
+When the example starts up, it will print "Starting OTA example..." then:
 
 1. Connect to the AP with configured SSID and password.
 2. Connect to the HTTP server and download the new image.
 3. Write the image to flash, and configure the next boot from this image.
 4. Reboot
 
-# Troubleshooting
+## Troubleshooting
 
 * Check your PC can ping the ESP32 at its IP, and that the IP, AP and other configuration settings are correct in menuconfig.
 * Check if any firewall software is preventing incoming connections on the PC.
-* Check you can see the configured file (default hello-world.bin) if you browse the file listing at http://127.0.0.1/
+* Check whether you can see the configured file (default hello-world.bin), by checking the output of following command:
+
+ ```
+ curl -v https://<host-ip-address>:<host-port>/<firmware-image-filename>
+ ```
+
 * If you have another PC or a phone, try viewing the file listing from the separate host.
 
-## Error "ota_begin error err=0x104"
+### Error "ota_begin error err=0x104"
 
 If you see this error then check that the configured (and actual) flash size is large enough for the partitions in the partition table. The default "two OTA slots" partition table only works with 4MB flash size. To use OTA with smaller flash sizes, create a custom partition table CSV (look in components/partition_table) and configure it in menuconfig.
 
 If changing partition layout, it is usually wise to run "make erase_flash" between steps.
-
-## Production Implementation
-
-If scaling this example for production use, please consider:
-
-* Using an encrypted communications channel such as HTTPS.
-* Dealing with timeouts or WiFi disconnections while flashing.
similarity index 85%
rename from examples/system/ota/Makefile
rename to examples/system/ota/native_ota_example/Makefile
index 7ffb10234f10749ebfdde97e79470f3bd88bd631..3bcbefac0d8370d5f6e63a7fdeab1c36155b8b3f 100644 (file)
@@ -3,7 +3,7 @@
 # project subdirectory.
 #
 
-PROJECT_NAME := ota
+PROJECT_NAME := native_ota
 
 include $(IDF_PATH)/make/project.mk
 
diff --git a/examples/system/ota/native_ota_example/README.md b/examples/system/ota/native_ota_example/README.md
new file mode 100644 (file)
index 0000000..be57ce5
--- /dev/null
@@ -0,0 +1,7 @@
+# Native OTA example
+
+This example is based on `app_update` component's APIs.
+
+## Configuration
+
+Refer the README.md in the parent directory for the setup details.
\ No newline at end of file
similarity index 52%
rename from examples/system/ota/main/Kconfig.projbuild
rename to examples/system/ota/native_ota_example/main/Kconfig.projbuild
index 2d4b8c43606db2a111e14ab03a573ee81d115b7d..05965e9426ccc0818b7466139073de2ed1a80f0d 100644 (file)
@@ -14,27 +14,12 @@ config WIFI_PASSWORD
 
                Can be left blank if the network has no security set.
 
-config SERVER_IP
-    string "HTTP Server IP"
-       default "192.168.0.3"
+config FIRMWARE_UPG_URL
+    string "HTTP Server URL"
+    default "https://192.168.0.3:8070/hello-world.bin"
        help
                HTTP Server IP to download the image file from.
 
                See example README.md for details.
 
-config SERVER_PORT
-       string "HTTP Server Port"
-       default "8070"
-       help
-               HTTP Server port to connect to.
-               Should be chosen not to conflict with any other port used
-               on the system.
-
-config EXAMPLE_FILENAME
-       string "HTTP GET Filename"
-       default "/hello-world.bin"
-       help
-               Filename of the app image file to download for
-               the OTA update.
-
 endmenu
similarity index 62%
rename from examples/system/ota/main/component.mk
rename to examples/system/ota/native_ota_example/main/component.mk
index a98f634eae065626088ba907b2cda16000478d5b..93a42f552fbed2ed2829c9595777a8049ceac081 100644 (file)
@@ -2,3 +2,5 @@
 # "main" pseudo-component makefile.
 #
 # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
+COMPONENT_EMBED_TXTFILES :=  ${IDF_PATH}/examples/system/ota/server_certs/ca_cert.pem
similarity index 51%
rename from examples/system/ota/main/ota_example_main.c
rename to examples/system/ota/native_ota_example/main/native_ota_example.c
index b5e0f606255b6518283302226a5d3e57b8e8a385..0f83ca7ab64351b704524f33158ddec19e8b5246 100644 (file)
@@ -6,10 +6,6 @@
    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    CONDITIONS OF ANY KIND, either express or implied.
 */
-#include <string.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 #include "freertos/event_groups.h"
 #include "esp_event_loop.h"
 #include "esp_log.h"
 #include "esp_ota_ops.h"
+#include "esp_http_client.h"
+#include "esp_flash_partitions.h"
+#include "esp_partition.h"
 
 #include "nvs.h"
 #include "nvs_flash.h"
 
 #define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
 #define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
-#define EXAMPLE_SERVER_IP   CONFIG_SERVER_IP
-#define EXAMPLE_SERVER_PORT CONFIG_SERVER_PORT
-#define EXAMPLE_FILENAME CONFIG_EXAMPLE_FILENAME
+#define EXAMPLE_SERVER_URL CONFIG_FIRMWARE_UPG_URL
 #define BUFFSIZE 1024
-#define TEXT_BUFFSIZE 1024
+#define HASH_LEN 32 /* SHA-256 digest length */
 
-static const char *TAG = "ota";
+static const char *TAG = "native_ota_example";
 /*an ota data write buffer ready to write to the flash*/
 static char ota_write_data[BUFFSIZE + 1] = { 0 };
-/*an packet receive buffer*/
-static char text[BUFFSIZE + 1] = { 0 };
-/* an image total length*/
-static int binary_file_length = 0;
-/*socket id*/
-static int socket_id = -1;
+extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
+extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");
 
 /* FreeRTOS event group to signal when we are connected & ready to make a request */
 static EventGroupHandle_t wifi_event_group;
@@ -90,85 +83,15 @@ static void initialise_wifi(void)
     ESP_ERROR_CHECK( esp_wifi_start() );
 }
 
-/*read buffer by byte still delim ,return read bytes counts*/
-static int read_until(char *buffer, char delim, int len)
-{
-//  /*TODO: delim check,buffer check,further: do an buffer length limited*/
-    int i = 0;
-    while (buffer[i] != delim && i < len) {
-        ++i;
-    }
-    return i + 1;
-}
-
-/* resolve a packet from http socket
- * return true if packet including \r\n\r\n that means http packet header finished,start to receive packet body
- * otherwise return false
- * */
-static bool read_past_http_header(char text[], int total_len, esp_ota_handle_t update_handle)
-{
-    /* i means current position */
-    int i = 0, i_read_len = 0;
-    while (text[i] != 0 && i < total_len) {
-        i_read_len = read_until(&text[i], '\n', total_len);
-        // if we resolve \r\n line,we think packet header is finished
-        if (i_read_len == 2) {
-            int i_write_len = total_len - (i + 2);
-            memset(ota_write_data, 0, BUFFSIZE);
-            /*copy first http packet body to write buffer*/
-            memcpy(ota_write_data, &(text[i + 2]), i_write_len);
-
-            esp_err_t err = esp_ota_write( update_handle, (const void *)ota_write_data, i_write_len);
-            if (err != ESP_OK) {
-                ESP_LOGE(TAG, "Error: esp_ota_write failed (%s)!", esp_err_to_name(err));
-                return false;
-            } else {
-                ESP_LOGI(TAG, "esp_ota_write header OK");
-                binary_file_length += i_write_len;
-            }
-            return true;
-        }
-        i += i_read_len;
-    }
-    return false;
-}
-
-static bool connect_to_http_server()
+static void http_cleanup(esp_http_client_handle_t client)
 {
-    ESP_LOGI(TAG, "Server IP: %s Server Port:%s", EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);
-
-    int  http_connect_flag = -1;
-    struct sockaddr_in sock_info;
-
-    socket_id = socket(AF_INET, SOCK_STREAM, 0);
-    if (socket_id == -1) {
-        ESP_LOGE(TAG, "Create socket failed!");
-        return false;
-    }
-
-    // set connect info
-    memset(&sock_info, 0, sizeof(struct sockaddr_in));
-    sock_info.sin_family = AF_INET;
-    sock_info.sin_addr.s_addr = inet_addr(EXAMPLE_SERVER_IP);
-    sock_info.sin_port = htons(atoi(EXAMPLE_SERVER_PORT));
-
-    // connect to http server
-    http_connect_flag = connect(socket_id, (struct sockaddr *)&sock_info, sizeof(sock_info));
-    if (http_connect_flag == -1) {
-        ESP_LOGE(TAG, "Connect to server failed! errno=%d", errno);
-        close(socket_id);
-        return false;
-    } else {
-        ESP_LOGI(TAG, "Connected to server");
-        return true;
-    }
-    return false;
+    esp_http_client_close(client);
+    esp_http_client_cleanup(client);
 }
 
 static void __attribute__((noreturn)) task_fatal_error()
 {
     ESP_LOGE(TAG, "Exiting task due to fatal error...");
-    close(socket_id);
     (void)vTaskDelete(NULL);
 
     while (1) {
@@ -176,6 +99,16 @@ static void __attribute__((noreturn)) task_fatal_error()
     }
 }
 
+void print_sha256 (const uint8_t *image_hash, const char *label)
+{
+    char hash_print[HASH_LEN * 2 + 1];
+    hash_print[HASH_LEN * 2] = 0;
+    for (int i = 0; i < HASH_LEN; ++i) {
+        sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
+    }
+    ESP_LOGI(TAG, "%s: %s", label, hash_print);
+}
+
 static void ota_example_task(void *pvParameter)
 {
     esp_err_t err;
@@ -202,36 +135,23 @@ static void ota_example_task(void *pvParameter)
     xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
                         false, true, portMAX_DELAY);
     ESP_LOGI(TAG, "Connect to Wifi ! Start to Connect to Server....");
-
-    /*connect to http server*/
-    if (connect_to_http_server()) {
-        ESP_LOGI(TAG, "Connected to http server");
-    } else {
-        ESP_LOGE(TAG, "Connect to http server failed!");
-        task_fatal_error();
-    }
-
-    /*send GET request to http server*/
-    const char *GET_FORMAT =
-        "GET %s HTTP/1.0\r\n"
-        "Host: %s:%s\r\n"
-        "User-Agent: esp-idf/1.0 esp32\r\n\r\n";
-
-    char *http_request = NULL;
-    int get_len = asprintf(&http_request, GET_FORMAT, EXAMPLE_FILENAME, EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);
-    if (get_len < 0) {
-        ESP_LOGE(TAG, "Failed to allocate memory for GET request buffer");
+    
+    esp_http_client_config_t config = {
+        .url = EXAMPLE_SERVER_URL,
+        .cert_pem = (char *)server_cert_pem_start,
+    };
+    esp_http_client_handle_t client = esp_http_client_init(&config);
+    if (client == NULL) {
+        ESP_LOGE(TAG, "Failed to initialise HTTP connection");
         task_fatal_error();
     }
-    int res = send(socket_id, http_request, get_len, 0);
-    free(http_request);
-
-    if (res < 0) {
-        ESP_LOGE(TAG, "Send GET request to server failed");
+    err = esp_http_client_open(client, 0);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
+        esp_http_client_cleanup(client);
         task_fatal_error();
-    } else {
-        ESP_LOGI(TAG, "Send GET request to server succeeded");
     }
+    esp_http_client_fetch_headers(client);
 
     update_partition = esp_ota_get_next_update_partition(NULL);
     ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
@@ -241,55 +161,54 @@ static void ota_example_task(void *pvParameter)
     err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
     if (err != ESP_OK) {
         ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
+        http_cleanup(client);
         task_fatal_error();
     }
     ESP_LOGI(TAG, "esp_ota_begin succeeded");
 
-    bool resp_body_start = false, socket_flag = true, http_200_flag = false;
+    int binary_file_length = 0;
     /*deal with all receive packet*/
-    while (socket_flag) {
-        memset(text, 0, TEXT_BUFFSIZE);
-        memset(ota_write_data, 0, BUFFSIZE);
-        int buff_len = recv(socket_id, text, TEXT_BUFFSIZE, 0);
-        if (buff_len < 0) { /*receive error*/
-            ESP_LOGE(TAG, "Error: receive data error! errno=%d", errno);
+    while (1) {
+        int data_read = esp_http_client_read(client, ota_write_data, BUFFSIZE);
+        if (data_read < 0) {
+            ESP_LOGE(TAG, "Error: SSL data read error");
+            http_cleanup(client);
             task_fatal_error();
-        } else if (buff_len > 0 && !resp_body_start) {  /*deal with response header*/
-            // only start ota when server response 200 state code
-            if (strstr(text, "200") == NULL && !http_200_flag) {
-                ESP_LOGE(TAG, "ota url is invalid or bin is not exist");
-                task_fatal_error();
-            }
-            http_200_flag = true;
-            memcpy(ota_write_data, text, buff_len);
-            resp_body_start = read_past_http_header(text, buff_len, update_handle);
-        } else if (buff_len > 0 && resp_body_start) { /*deal with response body*/
-            memcpy(ota_write_data, text, buff_len);
-            err = esp_ota_write( update_handle, (const void *)ota_write_data, buff_len);
+        } else if (data_read > 0) {
+            err = esp_ota_write( update_handle, (const void *)ota_write_data, data_read);
             if (err != ESP_OK) {
-                ESP_LOGE(TAG, "Error: esp_ota_write failed (%s)!", esp_err_to_name(err));
+                http_cleanup(client);
                 task_fatal_error();
             }
-            binary_file_length += buff_len;
-            ESP_LOGI(TAG, "Have written image length %d", binary_file_length);
-        } else if (buff_len == 0) {  /*packet over*/
-            socket_flag = false;
-            ESP_LOGI(TAG, "Connection closed, all packets received");
-            close(socket_id);
-        } else {
-            ESP_LOGE(TAG, "Unexpected recv result");
+            binary_file_length += data_read;
+            ESP_LOGD(TAG, "Written image length %d", binary_file_length);
+        } else if (data_read == 0) {
+            ESP_LOGI(TAG, "Connection closed,all data received");
+            break;
         }
     }
-
     ESP_LOGI(TAG, "Total Write binary data length : %d", binary_file_length);
 
     if (esp_ota_end(update_handle) != ESP_OK) {
         ESP_LOGE(TAG, "esp_ota_end failed!");
+        http_cleanup(client);
         task_fatal_error();
     }
+
+    if (esp_partition_check_identity(esp_ota_get_running_partition(), update_partition) == true) {
+        ESP_LOGI(TAG, "The current running firmware is same as the firmware just downloaded");
+        int i = 0;
+        ESP_LOGI(TAG, "When a new firmware is available on the server, press the reset button to download it");
+        while(1) {
+            ESP_LOGI(TAG, "Waiting for a new firmware ... %d", ++i);
+            vTaskDelay(2000 / portTICK_PERIOD_MS);
+        }
+    }
+
     err = esp_ota_set_boot_partition(update_partition);
     if (err != ESP_OK) {
         ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
+        http_cleanup(client);
         task_fatal_error();
     }
     ESP_LOGI(TAG, "Prepare to restart system!");
@@ -299,9 +218,30 @@ static void ota_example_task(void *pvParameter)
 
 void app_main()
 {
+    uint8_t sha_256[HASH_LEN] = { 0 };
+    esp_partition_t partition;
+
+    // get sha256 digest for the partition table
+    partition.address   = ESP_PARTITION_TABLE_OFFSET;
+    partition.size      = ESP_PARTITION_TABLE_MAX_LEN;
+    partition.type      = ESP_PARTITION_TYPE_DATA;
+    esp_partition_get_sha256(&partition, sha_256);
+    print_sha256(sha_256, "SHA-256 for the partition table: ");
+
+    // get sha256 digest for bootloader
+    partition.address   = ESP_BOOTLOADER_OFFSET;
+    partition.size      = ESP_PARTITION_TABLE_OFFSET;
+    partition.type      = ESP_PARTITION_TYPE_APP;
+    esp_partition_get_sha256(&partition, sha_256);
+    print_sha256(sha_256, "SHA-256 for bootloader: ");
+
+    // get sha256 digest for running partition
+    esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);
+    print_sha256(sha_256, "SHA-256 for current firmware: ");
+
     // Initialize NVS.
     esp_err_t err = nvs_flash_init();
-    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         // OTA app partition table has a smaller NVS partition size than the non-OTA
         // partition table. This size mismatch may cause NVS initialization to fail.
         // If this happens, we erase NVS partition and initialize NVS again.
diff --git a/examples/system/ota/server_certs/ca_cert.pem b/examples/system/ota/server_certs/ca_cert.pem
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/examples/system/ota/simple_ota_example/Makefile b/examples/system/ota/simple_ota_example/Makefile
new file mode 100644 (file)
index 0000000..63bca1a
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := simple_ota
+
+include $(IDF_PATH)/make/project.mk
+
diff --git a/examples/system/ota/simple_ota_example/README.md b/examples/system/ota/simple_ota_example/README.md
new file mode 100644 (file)
index 0000000..437964f
--- /dev/null
@@ -0,0 +1,7 @@
+# Simple OTA example
+
+This example is based on `http_firmware_upgrade` component's APIs.
+
+## Configuration
+
+Refer README.md in the parent directory for setup details
\ No newline at end of file
diff --git a/examples/system/ota/simple_ota_example/main/Kconfig.projbuild b/examples/system/ota/simple_ota_example/main/Kconfig.projbuild
new file mode 100644 (file)
index 0000000..38bf5cb
--- /dev/null
@@ -0,0 +1,21 @@
+menu "Example Configuration"
+
+config WIFI_SSID
+    string "WiFi SSID"
+    default "myssid"
+    help
+       SSID (network name) for the example to connect to.
+
+config WIFI_PASSWORD
+    string "WiFi Password"
+    default "mypassword"
+    help
+       WiFi password (WPA or WPA2) for the example to use.
+
+config FIRMWARE_UPGRADE_URL
+    string "firmware upgrade url endpoint"
+    default "https://192.168.0.3:8070/hello-world.bin"
+    help
+        URL of server which hosts the firmware
+        image.
+endmenu
diff --git a/examples/system/ota/simple_ota_example/main/component.mk b/examples/system/ota/simple_ota_example/main/component.mk
new file mode 100644 (file)
index 0000000..93a42f5
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
+COMPONENT_EMBED_TXTFILES :=  ${IDF_PATH}/examples/system/ota/server_certs/ca_cert.pem
diff --git a/examples/system/ota/simple_ota_example/main/simple_ota_example.c b/examples/system/ota/simple_ota_example/main/simple_ota_example.c
new file mode 100644 (file)
index 0000000..7972f8b
--- /dev/null
@@ -0,0 +1,147 @@
+/* OTA example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+
+#include "esp_system.h"
+#include "esp_wifi.h"
+#include "esp_event_loop.h"
+#include "esp_log.h"
+#include "esp_ota_ops.h"
+#include "esp_http_client.h"
+#include "esp_https_ota.h"
+
+#include "nvs.h"
+#include "nvs_flash.h"
+
+static const char *TAG = "simple_ota_example";
+extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
+extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");
+
+/* FreeRTOS event group to signal when we are connected & ready to make a request */
+static EventGroupHandle_t wifi_event_group;
+
+/* The event group allows multiple bits for each event,
+   but we only care about one event - are we connected
+   to the AP with an IP? */
+const int CONNECTED_BIT = BIT0;
+
+esp_err_t _http_event_handler(esp_http_client_event_t *evt)
+{
+    switch(evt->event_id) {
+        case HTTP_EVENT_ERROR:
+            ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
+            break;
+        case HTTP_EVENT_ON_CONNECTED:
+            ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
+            break;
+        case HTTP_EVENT_HEADER_SENT:
+            ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
+            break;
+        case HTTP_EVENT_ON_HEADER:
+            ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
+            break;
+        case HTTP_EVENT_ON_DATA:
+            ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
+            break;
+        case HTTP_EVENT_ON_FINISH:
+            ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
+            break;
+        case HTTP_EVENT_DISCONNECTED:
+            ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
+            break;
+    }
+    return ESP_OK;
+}
+
+static esp_err_t event_handler(void *ctx, system_event_t *event)
+{
+    switch (event->event_id) {
+    case SYSTEM_EVENT_STA_START:
+        esp_wifi_connect();
+        break;
+    case SYSTEM_EVENT_STA_GOT_IP:
+        xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
+        break;
+    case SYSTEM_EVENT_STA_DISCONNECTED:
+        /* This is a workaround as ESP32 WiFi libs don't currently
+           auto-reassociate. */
+        esp_wifi_connect();
+        xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
+        break;
+    default:
+        break;
+    }
+    return ESP_OK;
+}
+
+static void initialise_wifi(void)
+{
+    tcpip_adapter_init();
+    wifi_event_group = xEventGroupCreate();
+    ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
+    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
+    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
+    wifi_config_t wifi_config = {
+        .sta = {
+            .ssid = CONFIG_WIFI_SSID,
+            .password = CONFIG_WIFI_PASSWORD,
+        },
+    };
+    ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
+    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
+    ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
+    ESP_ERROR_CHECK( esp_wifi_start() );
+}
+
+void simple_ota_example_task(void * pvParameter)
+{
+    ESP_LOGI(TAG, "Starting OTA example...");
+
+    /* Wait for the callback to set the CONNECTED_BIT in the
+       event group.
+    */
+    xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
+                        false, true, portMAX_DELAY);
+    ESP_LOGI(TAG, "Connect to Wifi ! Start to Connect to Server....");
+    
+    esp_http_client_config_t config = {
+        .url = CONFIG_FIRMWARE_UPGRADE_URL,
+        .cert_pem = (char *)server_cert_pem_start,
+        .event_handler = _http_event_handler,
+    };
+    esp_err_t ret = esp_https_ota(&config);
+    if (ret == ESP_OK) {
+        esp_restart();
+    } else {
+        ESP_LOGE(TAG, "Firmware Upgrades Failed");
+    }
+    while (1) {
+        vTaskDelay(1000 / portTICK_PERIOD_MS);
+    }
+}
+
+void app_main()
+{
+    // Initialize NVS.
+    esp_err_t err = nvs_flash_init();
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
+        // OTA app partition table has a smaller NVS partition size than the non-OTA
+        // partition table. This size mismatch may cause NVS initialization to fail.
+        // If this happens, we erase NVS partition and initialize NVS again.
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        err = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK( err );
+
+    initialise_wifi();
+    xTaskCreate(&simple_ota_example_task, "ota_example_task", 8192, NULL, 5, NULL);
+}
diff --git a/examples/system/ota/simple_ota_example/sdkconfig.defaults b/examples/system/ota/simple_ota_example/sdkconfig.defaults
new file mode 100644 (file)
index 0000000..2289a82
--- /dev/null
@@ -0,0 +1,4 @@
+# Default sdkconfig parameters to use the OTA
+# partition table layout, with a 4MB flash size
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
+CONFIG_PARTITION_TABLE_TWO_OTA=y
index c03ab20eec64d4bfbe10ad4d6271816e9cc08d1d..74c4febe401e828390180146f1d5305de9ce7470 100644 (file)
@@ -87,7 +87,7 @@ static void init_ulp_program()
     ulp_set_wakeup_period(0, 20000);
 
     /* Start the program */
-    err = ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t));
+    err = ulp_run(&ulp_entry - RTC_SLOW_MEM);
     ESP_ERROR_CHECK(err);
 }
 
index 29d8eac9af59e7edbb4891735cd88471eac31d0a..fd7d4ef4387d35396366026c1325735418219e57 100644 (file)
@@ -89,6 +89,6 @@ static void start_ulp_program()
     ulp_sample_counter = 0;
 
     /* Start the program */
-    esp_err_t err = ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t));
+    esp_err_t err = ulp_run(&ulp_entry - RTC_SLOW_MEM);
     ESP_ERROR_CHECK(err);
 }
index 68e56ff654a6b7c2ae281cb329e34f1731425939..afb1428c52536b73fffd4aa8c52868f74113a27a 100644 (file)
@@ -375,7 +375,7 @@ void app_main()
 {
     // Initialize NVS
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK( nvs_flash_erase() );
         ret = nvs_flash_init();
     }
index bb4940f79b57ae61867b66ac9edc3a8fa4a0ee4f..ffeeb680b59a3bbd7ebe34aaa1537256d439af2d 100644 (file)
@@ -71,7 +71,7 @@ static void initialize_console()
 void app_main(void)
 {
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index f40b898bcf99956222e9cdd06772c9a7b0314934..d2e60fdfd1fb39bf7914a604a447d4e20bf407aa 100644 (file)
@@ -89,7 +89,7 @@ void app_main()
 {
     // Initialize NVS
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index ee82d859df67b7092ff992f0e1e1001239dbdf9a..fa27bf7f21ab4d59164c48f336f23f947ed517ab 100644 (file)
@@ -117,7 +117,7 @@ void app_main()
 {
     // Initialize NVS
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index ccc5590165e2fb26e2d300ac0cc45fa0df71c4bd..456e880eefceb0ce8ad334c447e5118d0660b064 100644 (file)
@@ -130,7 +130,7 @@ void app_main()
 {
     //Initialize NVS
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
       ESP_ERROR_CHECK(nvs_flash_erase());
       ret = nvs_flash_init();
     }
index 6fb8ad24683bafed472fd0be472a63e9ae41edd9..50ab8de9bc0bb71f05d5113403cee19711e50efb 100644 (file)
@@ -112,7 +112,7 @@ void app_main()
 {
     /* Initialize NVS — it is used to store PHY calibration data */
     esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
         ESP_ERROR_CHECK(nvs_flash_erase());
         ret = nvs_flash_init();
     }
index 2626fc074193be984285b47519174b04faa8613c..18361a7c90973924c972ae7c638770b3b5f7feba 100644 (file)
@@ -12,6 +12,7 @@ components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py
 docs/check_doc_warnings.sh
 docs/check_lang_folder_sync.sh
 docs/gen-kconfig-doc.py
+docs/gen-version-specific-includes.py
 tools/ci/apply_bot_filter.py
 tools/ci/build_examples.sh
 tools/ci/check-executable.sh
@@ -37,3 +38,4 @@ tools/kconfig/mconf
 tools/windows/eclipse_make.sh
 tools/test_idf_monitor/run_test_idf_monitor.py
 tools/mass_mfg/mfg_gen.py
+tools/unit-test-app/unit_test.py
index f75acb23409320a8f49aaff739c269e33b582dcd..c67a7ddeaeaa519e90976d32e85603c3eab4f210 100644 (file)
@@ -6,6 +6,7 @@ components/esptool_py/esptool                       @GENERAL_MIRROR_SERVER@/idf/
 components/json/cJSON                               @GENERAL_MIRROR_SERVER@/idf/cJSON.git                           ALLOW_TO_SYNC_FROM_PUBLIC
 components/libsodium/libsodium                      @GENERAL_MIRROR_SERVER@/idf/libsodium.git                       ALLOW_TO_SYNC_FROM_PUBLIC
 components/mbedtls/mbedtls                          @GENERAL_MIRROR_SERVER@/idf/mbedtls.git                         ALLOW_TO_SYNC_FROM_PUBLIC
+components/expat/expat                              @GENERAL_MIRROR_SERVER@/idf/libexpat.git                        ALLOW_TO_SYNC_FROM_PUBLIC
 components/micro-ecc/micro-ecc                      @GENERAL_MIRROR_SERVER@/idf/micro-ecc.git                       ALLOW_TO_SYNC_FROM_PUBLIC
 components/nghttp/nghttp2                           @GENERAL_MIRROR_SERVER@/idf/nghttp2.git                         ALLOW_TO_SYNC_FROM_PUBLIC
 components/spiffs/spiffs                            @GENERAL_MIRROR_SERVER@/idf/spiffs.git                          ALLOW_TO_SYNC_FROM_PUBLIC
index 0193cb6c70e5c42295181921cb7bda7df233cf9b..091a961549b471f0ee3e1bb546b27d4975af358d 100644 (file)
@@ -259,7 +259,7 @@ class BaseDUT(object):
     :param kwargs: extra args for DUT to create ports
     """
 
-    DEFAULT_EXPECT_TIMEOUT = 5
+    DEFAULT_EXPECT_TIMEOUT = 10
     MAX_EXPECT_FAILURES_TO_SAVED = 10
 
     LOG_THREAD = _LogThread()
index 7c06ad7a6946d56d5ea167654f615f4889e73504..358992f3e33e5a1df3157ac5de58d751a1454984 100644 (file)
@@ -106,6 +106,28 @@ If you want to reproduce locally, you need to:
         * You can refer to [unit test document](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/unit-tests.html#running-unit-tests) to run test manually.
         * Or, you can use `tools/unit-test-app/unit_test.py` to run the test cases:
             * read document of tiny-test-fw, set correct `TEST_FW_PATH` and `IDF_PATH`
-            * modify `unit_test.py`, pass the test cases need to test as parameter (refer to test function doc string for supported parameter format) to test functions.
-            * use `python unit_test.py` to run test
+            * run `unit_test.py` (see examples below)
     * You can also use  `tools/tiny-test-fw/Runner.py` to run test cases (it will be the same as what Runner do). Please use `python Runner.py -c $CONFIG_FILE $IDF_PATH/tools/unit-test-app` command, where `CONFIG_FILE` is a YAML file with same name with CI job in `components/idf_test/unit_test/CIConfigs` (artifacts, need to be download from `assign_test` job).
+
+## Running unit tests on local machine by `unit_test.py`
+
+A couple of examples follow for running unit tests on local machine.
+
+```bash
+# run a simple unit test
+./unit_test.py "UART can do select()"
+# repeat the tests two times
+./unit_test.py -r 2 "UART can do select()"
+# use custom environment config file
+./unit_test.py -e /tmp/EnvConfigTemplate.yml "UART can do select()"
+# use custom application binary
+./unit_test.py -b /tmp/app.bin "UART can do select()"
+# run a list of unit tests
+./unit_test.py "UART can do select()" "concurent selects work"
+# add some options for unit tests
+./unit_test.py "UART can do select()",timeout:10 "concurent selects work",config:release,env_tag:UT_T2_1
+# run a multi stage test (type of test and child case numbers are autodetected)
+./unit_test.py "check a time after wakeup from deep sleep"
+# run a list of different unit tests (one simple and one multi stage test)
+./unit_test.py "concurent selects work" "NOINIT attributes behavior"
+```
index fa1adf6333eecd95f4ae54a53c71407def8a12c0..6beb85cb9ddc7e5648ec66ea066b1fe99ba1b8d4 100644 (file)
@@ -309,6 +309,7 @@ static int print_test_menu(void)
             }
          }
      }
+     printf("\nEnter test for running.\n"); /* unit_test.py needs it for finding the end of test menu */
      return test_counter;
 }
 
diff --git a/tools/unit-test-app/configs/bt b/tools/unit-test-app/configs/bt
new file mode 100644 (file)
index 0000000..cc83ba1
--- /dev/null
@@ -0,0 +1,3 @@
+TEST_COMPONENTS=bt
+CONFIG_BT_ENABLED=y
+CONFIG_UNITY_FREERTOS_STACK_SIZE=12288
index a01e42947d380497d7ee5665cb84bb2c41c94567..b83aec589e24195fa7be86372620c6e1913a8e15 100644 (file)
@@ -1 +1 @@
-EXCLUDE_COMPONENTS=libsodium
+EXCLUDE_COMPONENTS=libsodium bt
index f43b22a4c7f53e24f836d6f830f8c362e3b6e87f..7828480c97cf594c8c5d216d01618d2940e022e2 100644 (file)
@@ -1,2 +1,3 @@
 TEST_COMPONENTS=libsodium
+EXCLUDE_COMPONENTS=bt
 CONFIG_UNITY_FREERTOS_STACK_SIZE=12288
index 34f865f04aab1c10ce19b7696d9b7e15b23759a1..dc74b5a2d58047835cc90341f8b33bccbf65f6b4 100644 (file)
@@ -1,2 +1,2 @@
-EXCLUDE_COMPONENTS=libsodium
+EXCLUDE_COMPONENTS=libsodium bt
 CONFIG_SPIRAM_SUPPORT=y
index 6e178910f7761df2a1e9a4aeb9942260f06b2604..370039d160181a4d085446e8419c4045b085d8d3 100644 (file)
@@ -1,2 +1,3 @@
+EXCLUDE_COMPONENTS=bt
 CONFIG_OPTIMIZATION_LEVEL_RELEASE=y
 CONFIG_OPTIMIZATION_ASSERTIONS_SILENT=y
index a985c851aadf2617fcceb288b52d6e1f9225b418..29d0350f5f9c175b063b27020ec3d0365a797408 100644 (file)
@@ -1,3 +1,3 @@
-EXCLUDE_COMPONENTS=libsodium
+EXCLUDE_COMPONENTS=libsodium bt
 CONFIG_MEMMAP_SMP=n
 CONFIG_FREERTOS_UNICORE=y
old mode 100644 (file)
new mode 100755 (executable)
index 4ce625a..c1e6f96
@@ -1,3 +1,19 @@
+#!/usr/bin/env python
+#
+# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 """
 Test script for unit test case.
 """
@@ -6,6 +22,7 @@ import re
 import os
 import sys
 import time
+import argparse
 
 import threading
 
@@ -18,6 +35,7 @@ if test_fw_path and test_fw_path not in sys.path:
 import TinyFW
 import IDF
 import Utility
+import Env
 from DUT import ExpectTimeout
 from IDF.IDFApp import UT
 
@@ -27,9 +45,16 @@ RESET_PATTERN = re.compile(r"(ets [\w]{3}\s+[\d]{1,2} [\d]{4} [\d]{2}:[\d]{2}:[\
 EXCEPTION_PATTERN = re.compile(r"(Guru Meditation Error: Core\s+\d panic'ed \([\w].*?\))")
 ABORT_PATTERN = re.compile(r"(abort\(\) was called at PC 0x[a-eA-E\d]{8} on core \d)")
 FINISH_PATTERN = re.compile(r"1 Tests (\d) Failures (\d) Ignored")
+END_LIST_STR = r'\r?\nEnter test for running'
+TEST_PATTERN = re.compile(r'\((\d+)\)\s+"([^"]+)" ([^\r]+)\r?\n(' + END_LIST_STR + r')?')
+TEST_SUBMENU_PATTERN = re.compile(r'\s+\((\d+)\)\s+"[^"]+"\r?\n(?=(?=\()|(' + END_LIST_STR + r'))')
 
-STARTUP_TIMEOUT=10
+SIMPLE_TEST_ID = 0
+MULTI_STAGE_ID = 1
+MULTI_DEVICE_ID = 2
 
+STARTUP_TIMEOUT=10
+DEFAULT_TIMEOUT=20
 
 def format_test_case_config(test_case_data):
     """
@@ -104,6 +129,15 @@ def format_test_case_config(test_case_data):
 
     return case_config
 
+def replace_app_bin(dut, name, new_app_bin):
+    if new_app_bin is None:
+        return
+    search_pattern = '/{}.bin'.format(name)
+    for i, config in enumerate(dut.download_config):
+        if config.endswith(search_pattern):
+            dut.download_config[i] = new_app_bin
+            Utility.console_log("The replaced application binary is {}".format(new_app_bin), "O")
+            break
 
 @IDF.idf_unit_test(env_tag="UT_T1_1")
 def run_unit_test_cases(env, extra_data):
@@ -132,6 +166,8 @@ def run_unit_test_cases(env, extra_data):
     for ut_config in case_config:
         Utility.console_log("Running unit test for config: " + ut_config, "O")
         dut = env.get_dut("unit-test-app", app_path=ut_config)
+        if len(case_config[ut_config]) > 0:
+            replace_app_bin(dut, "unit-test-app", case_config[ut_config][0].get('app_bin'))
         dut.start_app()
 
         for one_case in case_config[ut_config]:
@@ -306,17 +342,18 @@ def get_case_info(one_case):
     return parent_case, child_case_num
 
 
-def get_dut(duts, env, name, ut_config):
+def get_dut(duts, env, name, ut_config, app_bin=None):
     if name in duts:
         dut = duts[name]
     else:
         dut = env.get_dut(name, app_path=ut_config)
         duts[name] = dut
+        replace_app_bin(dut, "unit-test-app", app_bin)
         dut.start_app()
     return dut
 
 
-def case_run(duts, ut_config, env, one_case, failed_cases):
+def case_run(duts, ut_config, env, one_case, failed_cases, app_bin):
     lock = threading.RLock()
     threads = []
     send_signal_list = []
@@ -327,7 +364,7 @@ def case_run(duts, ut_config, env, one_case, failed_cases):
     THREAD_TERMINATE_FLAG = False
 
     for i in range(case_num):
-        dut = get_dut(duts, env, "dut%d" % i, ut_config)
+        dut = get_dut(duts, env, "dut%d" % i, ut_config, app_bin)
         threads.append(Handler(dut, send_signal_list, lock,
                                parent_case, i, one_case["timeout"]))
     for thread in threads:
@@ -374,7 +411,7 @@ def run_multiple_devices_cases(env, extra_data):
     for ut_config in case_config:
         Utility.console_log("Running unit test for config: " + ut_config, "O")
         for one_case in case_config[ut_config]:
-            case_run(DUTS, ut_config, env, one_case, failed_cases)
+            case_run(DUTS, ut_config, env, one_case, failed_cases, one_case.get('app_bin'))
 
     if failed_cases:
         Utility.console_log("Failed Cases:", color="red")
@@ -405,6 +442,8 @@ def run_multiple_stage_cases(env, extra_data):
     for ut_config in case_config:
         Utility.console_log("Running unit test for config: " + ut_config, "O")
         dut = env.get_dut("unit-test-app", app_path=ut_config)
+        if len(case_config[ut_config]) > 0:
+            replace_app_bin(dut, "unit-test-app", case_config[ut_config][0].get('app_bin'))
         dut.start_app()
 
         for one_case in case_config[ut_config]:
@@ -512,9 +551,132 @@ def run_multiple_stage_cases(env, extra_data):
             Utility.console_log("\t" + _case_name, color="red")
         raise AssertionError("Unit Test Failed")
 
+def detect_update_unit_test_info(env, extra_data, app_bin):
+
+    case_config = format_test_case_config(extra_data)
+
+    for ut_config in case_config:
+        dut = env.get_dut("unit-test-app", app_path=ut_config)
+        replace_app_bin(dut, "unit-test-app", app_bin)
+        dut.start_app()
+
+        dut.write("-", flush=False)
+        dut.expect_any(UT_APP_BOOT_UP_DONE, "0 Tests 0 Failures 0 Ignored", timeout=STARTUP_TIMEOUT)
+
+        # get the list of test cases
+        dut.write("")
+        dut.expect("Here's the test menu, pick your combo:", timeout=DEFAULT_TIMEOUT)
+
+        def find_update_dic(name, t, timeout, child_case_num=None):
+            for dic in extra_data:
+                if dic['name'] == name:
+                    dic['type'] = t
+                    if 'timeout' not in dic:
+                        dic['timeout'] = timeout
+                    if child_case_num:
+                        dic['child case num'] = child_case_num
+
+        try:
+            while True:
+                data = dut.expect(TEST_PATTERN, timeout=DEFAULT_TIMEOUT)
+                test_case_name = data[1]
+                m = re.search(r'\[timeout=(\d+)\]', data[2])
+                if m:
+                    timeout = int(m.group(1))
+                else:
+                    timeout = 30
+                m = re.search(r'\[multi_stage\]', data[2])
+                if m:
+                    test_case_type = MULTI_STAGE_ID
+                else:
+                    m = re.search(r'\[multi_device\]', data[2])
+                    if m:
+                        test_case_type = MULTI_DEVICE_ID
+                    else:
+                        test_case_type = SIMPLE_TEST_ID
+                        find_update_dic(test_case_name, test_case_type, timeout)
+                        if data[3] and re.search(END_LIST_STR, data[3]):
+                            break
+                        continue
+                # find the last submenu item
+                data = dut.expect(TEST_SUBMENU_PATTERN, timeout=DEFAULT_TIMEOUT)
+                find_update_dic(test_case_name, test_case_type, timeout, child_case_num=int(data[0]))
+                if data[1] and re.search(END_LIST_STR, data[1]):
+                    break
+            # check if the unit test case names are correct, i.e. they could be found in the device
+            for dic in extra_data:
+                if 'type' not in dic:
+                    raise ValueError("Unit test \"{}\" doesn't exist in the flashed device!".format(dic.get('name')))
+        except ExpectTimeout:
+            Utility.console_log("Timeout during getting the test list", color="red")
+        finally:
+            dut.close()
+
+        # These options are the same for all configs, therefore there is no need to continue
+        break
 
 if __name__ == '__main__':
-    run_multiple_devices_cases(extra_data={"name":  "gpio master/slave test example",
-                                           "child case num": 2,
-                                           "config": "release",
-                                           "env_tag": "UT_T2_1"})
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        '--repeat', '-r',
+        help='Number of repetitions for the test(s). Default is 1.',
+        type=int,
+        default=1
+    )
+    parser.add_argument("--env_config_file", "-e",
+        help="test env config file",
+        default=None
+    )
+    parser.add_argument("--app_bin", "-b",
+        help="application binary file for flashing the chip",
+        default=None
+    )
+    parser.add_argument(
+        'test',
+        help='Comma separated list of <option>:<argument> where option can be "name" (default), "child case num", \
+                "config", "timeout".',
+        nargs='+'
+    )
+    args = parser.parse_args()
+    list_of_dicts = []
+    for test in args.test:
+        test_args = test.split(r',')
+        test_dict = dict()
+        for test_item in test_args:
+            if len(test_item) == 0:
+                continue
+            pair = test_item.split(r':')
+            if len(pair) == 1 or pair[0] is 'name':
+                test_dict['name'] = pair[0]
+            elif len(pair) == 2:
+                if pair[0] == 'timeout' or pair[0] == 'child case num':
+                    test_dict[pair[0]] = int(pair[1])
+                else:
+                    test_dict[pair[0]] = pair[1]
+            else:
+                raise ValueError('Error in argument item {} of {}'.format(test_item, test))
+        test_dict['app_bin'] = args.app_bin
+        list_of_dicts.append(test_dict)
+
+    TinyFW.set_default_config(env_config_file=args.env_config_file)
+
+    env_config = TinyFW.get_default_config()
+    env_config['app'] = UT
+    env_config['dut'] = IDF.IDFDUT
+    env_config['test_suite_name'] = 'unit_test_parsing'
+    env = Env.Env(**env_config)
+    detect_update_unit_test_info(env, extra_data=list_of_dicts, app_bin=args.app_bin)
+
+    for i in range(1, args.repeat+1):
+        if args.repeat > 1:
+            Utility.console_log("Repetition {}".format(i), color="green")
+        for dic in list_of_dicts:
+            t = dic.get('type', SIMPLE_TEST_ID)
+            if t == SIMPLE_TEST_ID:
+                run_unit_test_cases(extra_data=dic)
+            elif t == MULTI_STAGE_ID:
+                run_multiple_stage_cases(extra_data=dic)
+            elif t == MULTI_DEVICE_ID:
+                run_multiple_devices_cases(extra_data=dic)
+            else:
+                raise ValueError('Unknown type {} of {}'.format(t, dic.get('name')))