pax_global_header00006660000000000000000000000064141720321340014507gustar00rootroot0000000000000052 comment=e56424c825752cbc23a34fc685d9d958adc30e62 mfgtools-uuu_1.4.193/000077500000000000000000000000001417203213400144165ustar00rootroot00000000000000mfgtools-uuu_1.4.193/.gitignore000066400000000000000000000001661417203213400164110ustar00rootroot00000000000000Debug Release gitversion.h *.user .vs CMakeFiles *.cmake *.swp *.a *.so uuu/uuu Makefile CMakeCache.txt *.clst *.snap mfgtools-uuu_1.4.193/.gitmodules000066400000000000000000000003521417203213400165730ustar00rootroot00000000000000[submodule "libusb"] path = libusb url = https://github.com/nxpfrankli/libusb.git [submodule "zlib"] path = zlib url = https://github.com/madler/zlib.git [submodule "bzip2"] path = bzip2 url = git://sourceware.org/git/bzip2.git mfgtools-uuu_1.4.193/.travis.yml000066400000000000000000000013111417203213400165230ustar00rootroot00000000000000language: c++ matrix: include: - os: osx osx_image: xcode9.4 compiler: clang - os: osx osx_image: xcode9.4 compiler: gcc - os: osx osx_image: xcode10.1 compiler: clang - os: osx osx_image: xcode10.1 compiler: gcc - os: osx osx_image: xcode11.6 compiler: clang - os: osx osx_image: xcode11.6 compiler: gcc addons: homebrew: update: true packages: - cmake - libusb - openssl - pkg-config script: - cmake -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl . && make mfgtools-uuu_1.4.193/CMakeLists.txt000066400000000000000000000020201417203213400171500ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.4) project(uuu) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_SKIP_RPATH ON) option(BUILD_DOC "Build documentation" OFF) add_subdirectory(libuuu) add_subdirectory(uuu) if (BUILD_DOC) # check if Doxygen is installed find_package(Doxygen) if (DOXYGEN_FOUND) # set input and output files set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) # request to configure the file configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY) message("Doxygen build started") # note the option ALL which allows to build the docs together with the application add_custom_target( doc_doxygen ALL COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating documentation with Doxygen" VERBATIM ) else (DOXYGEN_FOUND) message("Doxygen need to be installed to generate the doxygen documentation") endif (DOXYGEN_FOUND) endif (BUILD_DOC) mfgtools-uuu_1.4.193/Doxyfile.in000066400000000000000000000010341417203213400165270ustar00rootroot00000000000000PROJECT_NAME = "uuu" PROJECT_BRIEF = "uuu (Universal Update Utility), mfgtools 3.0" DOXYFILE_ENCODING = UTF-8 OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/docs/ INPUT = @CMAKE_CURRENT_SOURCE_DIR@/uuu/ @CMAKE_CURRENT_SOURCE_DIR@/libuuu/ RECURSIVE = YES EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_PACKAGE = YES EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = YES CALL_GRAPH = YES CALLER_GRAPH = YES mfgtools-uuu_1.4.193/LICENSE000066400000000000000000000026761417203213400154360ustar00rootroot00000000000000Copyright 2018 NXP. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Freescale Semiconductor nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. mfgtools-uuu_1.4.193/README.md000066400000000000000000000104431417203213400156770ustar00rootroot00000000000000# uuu (Universal Update Utility), mfgtools 3.0 [![Build status](https://ci.appveyor.com/api/projects/status/github/NXPmicro/mfgtools?svg=true)](https://ci.appveyor.com/project/nxpfrankli/mfgtools-kvqcg) [![Build Status](https://travis-ci.com/NXPmicro/mfgtools.svg?branch=master)](https://travis-ci.com/NXPmicro/mfgtools) ![GitHub](https://img.shields.io/github/license/NXPmicro/mfgtools.svg) [![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/universal-update-utility) sudo snap install universal-update-utility; Freescale/NXP I.MX Chip image deploy tools. **original linux version uses "linux" branch, windows version uses "windows" branch** uuu (universal update utility) for nxp imx chips -- libuuu-1.0.1-gffd9837 Succeded:0 Failed:3 Wait for Known USB Devices to Appear... 1:11 5/5 [ ] SDP: jump -f u-boot-dtb.imx -ivtinitramf.... 2:1 1/5 [===> ] SDP: boot -f u-boot-imx7dsabresd_sd.imx .... # Key features - The real cross platform. Linux, Windows, MacOS(not test yet) - Multi devices program support - Daemon mode support - Few depedencies (only libusb, zlibc, libbz2) - Firmware (uboot/kernel) uses WCID to auto load the winusb driver on the Windows side. Windows7 users need to install the winusb driver from https://zadig.akeo.ie/ Windows10 will install the driver automatically. # Examples: ``` uuu u-boot.imx Download u-boot.imx via HID device uuu list.uu Run all the commands in list.uu uuu -s Enter shell mode. Input command. uuu -v u-boot.imx verbose mode uuu -d u-boot.imx Once it detects the attachement of a known device, download boot.imx. u-boot.imx can be replaced, new file will be download once board reset. Do not unplug the SD card, write to the SD card, nor plug in a SD card when debugging uboot. uuu -b emmc u-boot.imx write u-boot.imx to emmc boot partition. u-boot.imx need enable fastboot uuu -b emmc_all u-boot.imx sdcard.bz2\* decompress sdcard.bz2 file and download the whole image into emmc ``` # Prebuilt Image and pdf document The prebuilt image and document are here: - https://github.com/NXPmicro/mfgtools/releases - UUU.pdf is snapshot of [wiki](https://github.com/NXPmicro/mfgtools/wiki) # How to Build: ## Windows - `git clone https://github.com/NXPmicro/mfgtools.git` - `cd mfgtools` - `git submodule init` - `git submodule update` - `open msvs/uuu.sln with Visual Studio 2017` Visual Studio Note that, since uuu is an OSI compliant Open Source project, you are entitled to download and use the freely available Visual Studio Community Edition to build, run or develop for uuu. As per the Visual Studio Community Edition license this applies regardless of whether you are an individual or a corporate user. ## Linux - `git clone https://github.com/NXPmicro/mfgtools.git` - `cd mfgtools` - `sudo apt-get install libusb-1.0-0-dev libbz2-dev pkg-config cmake libssl-dev g++` - `cmake . && make` The above commands build mfgtools in source. To build it out of source (requires cmake 3.13 or newer): - `cmake -S . -B build` - `cmake --build build --target all` For cmake prior 3.13: - `mkdir build && cd build` - `cmake .. && make` ## macOS - `git clone https://github.com/NXPmicro/mfgtools.git` - `cd mfgtools` - `brew install cmake libusb openssl pkg-config` - `cmake -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl . && make` Note that we assume [brew](https://brew.sh) is installed and can be used to resolve dependencies as shown above. The remaining dependency `libbz2` can be resolved via the XCode supplied libraries. # Run environment - Windows 10 64 bit - Linux (Ubuntu) 64 bit - macOS (Catalina) - 32 bit systems will have problems with big files. # License uuu is licensed under the BSD license. See LICENSE. The BSD licensed prebuilt Windows binary version of uuu is statically linked with the LGPL libusb library, which remains LGPL. - bzip2 (BSD license) is from https://github.com/enthought/bzip2-1.0.6 - zlib (zlib license) is from https://github.com/madler/zlib.git - libusb (LGPL-2.1) is from https://github.com/libusb/libusb.git mfgtools-uuu_1.4.193/appveyor.yml000066400000000000000000000174241417203213400170160ustar00rootroot00000000000000version: 1.4.{build} image: - Visual Studio 2019 - Visual Studio 2017 - Ubuntu1604 - macOS configuration: - Debug - Release platform: - x86 - x64 init: - sh: if [ "${CONFIGURATION}" = "Debug" ] ; then exit 0; fi - sh: if [ "${PLATFORM}" = "x86" ]; then exit 0; fi skip_tags: true install: - cmd: echo %APPVEYOR_BUILD_FOLDER% - cmd: git submodule update --init - cmd: cd %APPVEYOR_BUILD_FOLDER%\libusb - cmd: cd .. - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = "macOS" ]; then brew install libusb pkg-config; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then sudo apt-get update; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then sudo DEBIAN_FRONTEND=noninteractive apt-get --yes --force-yes install libusb-1.0-0-dev libbz2-dev asciidoc rename; fi build_script: # below powershell actions equals to retarget projects to newest SDK and tool v142 in visual studio 2019 - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc msvc\uuu.vcxproj) -replace '141', '142' | Out-File -encoding ASCII msvc\uuu.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc msvc\uuu.vcxproj) -replace '10.0.16299.0', '10.0' | Out-File -encoding ASCII msvc\uuu.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc msvc\bzip2.vcxproj) -replace '141', '142' | Out-File -encoding ASCII msvc\bzip2.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc msvc\bzip2.vcxproj) -replace '10.0.16299.0', '10.0' | Out-File -encoding ASCII msvc\bzip2.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc msvc\libuuu.vcxproj) -replace '141', '142' | Out-File -encoding ASCII msvc\libuuu.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc msvc\libuuu.vcxproj) -replace '10.0.16299.0', '10.0' | Out-File -encoding ASCII msvc\libuuu.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc msvc\zlib.vcxproj) -replace '141', '142' | Out-File -encoding ASCII msvc\zlib.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc msvc\zlib.vcxproj) -replace '10.0.16299.0', '10.0' | Out-File -encoding ASCII msvc\zlib.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc libusb\msvc\libusb_dll_2017.vcxproj) -replace '10.0.16299.0', '10.0' | Out-File -encoding ASCII libusb\msvc\libusb_dll_2017.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc libusb\msvc\libusb_dll_2017.vcxproj) -replace '141', '142' | Out-File -encoding ASCII libusb\msvc\libusb_dll_2017.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc msvc\uuu-static-link.vcxproj) -replace '141', '142' | Out-File -encoding ASCII msvc\uuu-static-link.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc msvc\uuu-static-link.vcxproj) -replace '10.0.16299.0', '10.0' | Out-File -encoding ASCII msvc\uuu-static-link.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc libusb\msvc\libusb_static_2017.vcxproj) -replace '10.0.16299.0', '10.0' | Out-File -encoding ASCII libusb\msvc\libusb_static_2017.vcxproj} - ps: If($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2019") {(gc libusb\msvc\libusb_static_2017.vcxproj) -replace '141', '142' | Out-File -encoding ASCII libusb\msvc\libusb_static_2017.vcxproj} - cmd: if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2019" (msbuild %APPVEYOR_BUILD_FOLDER%/msvc/uuu.sln /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll") #coverity tool is only available to visual studio 2017 imagine in appveyor - cmd: if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2017" (cov-build --dir cov-int msbuild %APPVEYOR_BUILD_FOLDER%/msvc/uuu.sln /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll") - cmd: if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2017" (7z a -tzip mfg.zip cov-int) - cmd: if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2017" (curl --form token=%coverity_token% --form email=frank.li@nxp.com --form file=@mfg.zip --form version="automation test" --form description="testing coverity automation" https://scan.coverity.com/builds?project=NXPmicro%2Fmfgtools) - cmd: git clean -dxf . - cmd: msbuild %APPVEYOR_BUILD_FOLDER%/msvc/uuu-static-link.sln /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - cmd: if exist %APPVEYOR_BUILD_FOLDER%\msvc\x64\release\uuu.exe cp %APPVEYOR_BUILD_FOLDER%\msvc\x64\release\uuu.exe %APPVEYOR_BUILD_FOLDER%\uuu.exe - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = "macOS" ]; then export PATH="/usr/local/Cellar/pkg-config/0.29.2_3/bin:${PATH}"; pkg-config --list-all; cmake -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl; else cmake -D 'STATIC=1' .; fi - sh: make - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = "macOS" ]; then ls uuu; mv uuu/uuu uuu/uuu_mac; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then git submodule init; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then git submodule update; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then git archive --prefix "uuu-${APPVEYOR_BUILD_VERSION}/" -o "uuu_source-${APPVEYOR_BUILD_VERSION}.tar" HEAD ; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then git submodule foreach --recursive "git archive --prefix=uuu-${APPVEYOR_BUILD_VERSION}/\$path/ --output=\$sha1.tar HEAD && tar --concatenate --file=$(pwd)/uuu_source-${APPVEYOR_BUILD_VERSION}.tar \$sha1.tar && rm \$sha1.tar" ; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then mkdir uuu-${APPVEYOR_BUILD_VERSION}; git describe --tags --long >uuu-${APPVEYOR_BUILD_VERSION}/.tarball-version ; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then tar -r uuu-${APPVEYOR_BUILD_VERSION}/.tarball-version -f uuu_source-${APPVEYOR_BUILD_VERSION}.tar ; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then gzip uuu_source-${APPVEYOR_BUILD_VERSION}.tar; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then tar xzf uuu_source-${APPVEYOR_BUILD_VERSION}.tar.gz && zip uuu_source-${APPVEYOR_BUILD_VERSION}.zip $(tar tf uuu_source-${APPVEYOR_BUILD_VERSION}.tar.gz); fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then git clone https://github.com/NXPmicro/mfgtools.wiki.git; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then cd mfgtools.wiki; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then rename -f 's/\.asciidoc$//' *; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then echo "" > UUU-docinfo.xml; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then git log -n25 --reverse --format="format:%h%cd%an%s" >> UUU-docinfo.xml; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then echo "" >> UUU-docinfo.xml; fi - sh: if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" != "macOS" ]; then a2x -L -a docinfo UUU; fi artifacts: - path: uuu.exe - path: uuu/uuu - path: uuu/uuu_mac - path: mfgtools.wiki/UUU.pdf - path: uuu_source-${APPVEYOR_BUILD_VERSION}.tar.gz - path: uuu_source-${APPVEYOR_BUILD_VERSION}.zip before_deploy: - cmd: '' deploy: - provider: GitHub description: prebuild for $(APPVEYOR_REPO_COMMIT) \n\n $(APPVEYOR_REPO_COMMIT_MESSAGE) auth_token: secure: SWWVkwSfPyVIaPChBBl+uAA3Fau9Rl5iNPQ9VRL8yyggXvc6wPcr/O9iXBMVM7Ju artifact: uuu.exe; uuu/uuu; uuu/uuu_mac; mfgtools.wiki/UUU.pdf; uuu_source-${APPVEYOR_BUILD_VERSION}.tar.gz; uuu_source-${APPVEYOR_BUILD_VERSION}.zip draft: true environment: coverity_token: secure: 5VvyV4fYfI6xPsqaeDHvBamkUmmVNjZj0J5pLLQ6NCw= mfgtools-uuu_1.4.193/bzip2/000077500000000000000000000000001417203213400154445ustar00rootroot00000000000000mfgtools-uuu_1.4.193/libusb/000077500000000000000000000000001417203213400156765ustar00rootroot00000000000000mfgtools-uuu_1.4.193/libuuu/000077500000000000000000000000001417203213400157235ustar00rootroot00000000000000mfgtools-uuu_1.4.193/libuuu/CMakeLists.txt000066400000000000000000000025501417203213400204650ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.4) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_SKIP_RPATH ON) find_package(BZip2 REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(LIBUSB REQUIRED libusb-1.0>=1.0.16) find_package(Threads) if (STATIC) set(OPENSSL_USE_STATIC_LIBS TRUE) endif() find_package(OpenSSL) if(OPENSSL_FOUND) set(UUUSSL "-DUUUSSL") set(UUUOPENSLL_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR}) endif() include_directories(${LIBUSB_INCLUDE_DIRS} ${UUUOPENSLL_INCLUDE_DIR} include) set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wstrict-aliasing -Wextra ${UUUSSL}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 ${UUUSSL}") set(SOURCES error.cpp buffer.cpp cmd.cpp config.cpp notify.cpp sdps.cpp trans.cpp usbhotplug.cpp version.cpp sdp.cpp gitversion.h fastboot.cpp zip.cpp fat.cpp tar.cpp rominfo.cpp http.cpp hidreport.cpp sparse.cpp ) set(generated_files_dir "${CMAKE_BINARY_DIR}/libuuu/gen") set(gitversion_h "${generated_files_dir}/gitversion.h") add_custom_command( OUTPUT gitversion.h PRE_BUILD COMMAND mkdir -p ${generated_files_dir} COMMAND sh -c 'cd ${CMAKE_CURRENT_SOURCE_DIR} && rm -f ${gitversion_h} && ./gen_ver.sh "${gitversion_h}.tmp" && mv -f "${gitversion_h}.tmp" "${gitversion_h}"' ) include_directories(${generated_files_dir}) #add_library( uuc SHARED ${SOURCES} )) add_library( uuc_s STATIC ${SOURCES} ) mfgtools-uuu_1.4.193/libuuu/backfile.h000066400000000000000000000032431417203213400176360ustar00rootroot00000000000000/* * Copyright 2020 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include class Backfile { public: const std::string& get_filename() const noexcept { return m_filename; } protected: std::string m_filename; }; mfgtools-uuu_1.4.193/libuuu/buffer.cpp000066400000000000000000001057651417203213400177160ustar00rootroot00000000000000/* * Copyright 2018-2019 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include "buffer.h" #include #include "liberror.h" #include #include #include "libcomm.h" #include "libuuu.h" #include "zip.h" #include "fat.h" #include "tar.h" #include #include "bzlib.h" #include "stdio.h" #include #include "http.h" #ifdef WIN32 #define stat_os _stat64 #elif defined(__APPLE__) #define stat_os stat #include "dirent.h" #else #define stat_os stat64 #include "dirent.h" #endif static map> g_filebuffer_map; static mutex g_mutex_map; #define MAGIC_PATH '>' string g_current_dir = ">"; void set_current_dir(const string &dir) { g_current_dir = MAGIC_PATH; g_current_dir += dir; } class FSBasic { public: virtual int get_file_timesample(const string &filename, uint64_t *ptime) = 0; virtual int load(const string &backfile, const string &filename, shared_ptr p, bool async) = 0; virtual bool exist(const string &backfile, const string &filename) = 0; virtual int for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) = 0; virtual int split(const string &filename, string *outbackfile, string *outfilename, bool dir=false) { string path = str_to_upper(filename); if (m_ext == nullptr || strlen(m_ext) == 0) { if(dir) { size_t pos = path.rfind("/"); if(pos == string::npos) { *outbackfile = MAGIC_PATH; *outbackfile += "./"; *outfilename = filename; } else { *outbackfile = filename.substr(0, pos); if(filename.size() >= pos + 1) *outfilename = filename.substr(pos + 1); else outfilename->clear(); } }else { *outbackfile = filename; } return 0; } string ext = m_ext; if(!dir) ext += "/"; size_t pos = path.rfind(ext); if (pos == string::npos) { set_last_err_string("can't find ext name in path"); return -1; } *outbackfile = filename.substr(0, pos + strlen(m_ext)); if(filename.size() >= pos + strlen(m_ext) + 1) *outfilename = filename.substr(pos + strlen(m_ext) + 1); else outfilename->clear(); return 0; } protected: const char * m_ext = nullptr; const char * m_Prefix = nullptr; }; static class FSFlat: public FSBasic { public: FSFlat() { m_ext = ""; } int get_file_timesample(const string &filename, uint64_t *ptime) override { struct stat_os st; if (stat_os(filename.c_str() + 1, &st)) { set_last_err_string("stat_os failure"); return -1; } *ptime = st.st_mtime; return 0; } bool exist(const string &backfile, const string &filename) override { struct stat_os st; return stat_os(backfile.c_str() + 1, &st) == 0 && ((st.st_mode & S_IFDIR) == 0); } int load(const string &backfile, const string &filename, shared_ptr p, bool async) override { struct stat_os st; if (stat_os(backfile.c_str() + 1, &st)) { set_last_err_string("stat_os failure"); return -1; } p->unmapfile(); if (p->mapfile(backfile.substr(1), st.st_size)) return -1; p->m_avaible_size = st.st_size; atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); return 0; } int for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) override { struct stat_os st; if(stat_os(backfile.c_str() + 1, &st)) { return -1; } if(st.st_mode & S_IFDIR) { #ifdef WIN32 string str = backfile.substr(1); if (filename.empty()) str += "/*"; else str += "/" + filename; WIN32_FIND_DATA fd; HANDLE handle = FindFirstFile(str.c_str(), &fd); BOOL b = false; do { if (handle == INVALID_HANDLE_VALUE) break; string path = backfile + "/" + fd.cFileName; if(fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) path += "/"; fn(path.c_str() + 1, p); } while (FindNextFile(handle, &fd)); CloseHandle(handle); return 0; #else DIR *dir; dir = opendir(backfile.c_str() + 1); struct dirent *dp; while ((dp=readdir(dir)) != nullptr) { string name = dp->d_name; if(name.substr(0, filename.size()) == filename || filename.empty()) { string path = backfile + "/" + name; if(dp->d_type == DT_DIR) path += "/"; fn(path.c_str() + 1, p); } } closedir(dir); return 0; #endif }else { return fn(backfile.c_str() + 1, p); } } } g_fsflat; class FSNetwork : public FSBasic { protected: int m_Port; public: int split(const string &filename, string *outbackfile, string *outfilename, bool dir = false) override { if (m_Prefix == nullptr) return -1; if (filename.size() < strlen(m_Prefix)) return -1; string path = str_to_upper(filename); if (path.compare(1, strlen(m_Prefix), m_Prefix) == 0) { size_t pos; pos = filename.find('/', 1 + strlen(m_Prefix)); *outbackfile = filename.substr(1 + strlen(m_Prefix), pos - 1 - strlen(m_Prefix)); size_t cpos; cpos = outbackfile->find(':'); if (cpos != string::npos) { m_Port = str_to_uint32(outbackfile->substr(cpos + 1)); *outbackfile = outbackfile->substr(0, cpos); } *outfilename = filename.substr(pos); return 0; } return -1; } }; static class FSHttp : public FSNetwork { public: FSHttp() { m_Prefix = "HTTP://"; m_Port = 80; } int load(const string &backfile, const string &filename, shared_ptr p, bool async) override; virtual bool exist(const string &backfile, const string &filename) override { return true; }; int for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) override { return 0; }; int get_file_timesample(const string &filename, uint64_t *ptime) override { return 0; }; }g_fshttp; static class FSHttps : public FSHttp { public: FSHttps() { m_Prefix = "HTTPS://"; m_Port = 443; } }g_fshttps; int http_load(shared_ptr http, shared_ptr p, string filename) { size_t max = 0x10000; uuu_notify ut; ut.type = uuu_notify::NOTIFY_DOWNLOAD_START; ut.str = (char*)filename.c_str(); call_notify(ut); ut.type = uuu_notify::NOTIFY_TRANS_SIZE; ut.total = p->size(); call_notify(ut); for (size_t i = 0; i < p->size(); i += max) { size_t sz = p->size() - i; if (sz > max) sz = max; if (http->HttpDownload((char*)(p->data() + i), sz) < 0) { atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_ERROR_BIT); p->m_request_cv.notify_all(); return -1; } p->m_avaible_size = i + sz; p->m_request_cv.notify_all(); ut.type = uuu_notify::NOTIFY_TRANS_POS; ut.total = i + sz; call_notify(ut); } atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); ut.type = uuu_notify::NOTIFY_DOWNLOAD_END; ut.str = (char*)filename.c_str(); call_notify(ut); return 0; } int FSHttp::load(const string &backfile, const string &filename, shared_ptr p, bool async) { shared_ptr http = make_shared(); if (http->HttpGetHeader(backfile, filename, m_Port, typeid(*this) == typeid(FSHttps))) return -1; size_t sz = http->HttpGetFileSize(); p->resize(sz); atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_KNOWN_SIZE); p->m_request_cv.notify_all(); if (async) { p->m_aync_thread = thread(http_load, http, p, backfile + filename); #ifdef WIN32 SetThreadPriority(p->m_aync_thread.native_handle(), THREAD_PRIORITY_BELOW_NORMAL); #endif } else { if (http_load(http, p, backfile + filename)) return -1; p->m_avaible_size = p->m_DataSize; atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); } return 0; } class FSBackFile : public FSBasic { public: int get_file_timesample(const string &filename, uint64_t *ptime) override; }; static class FSZip : public FSBackFile { public: FSZip() { m_ext = ".ZIP"; }; int load(const string &backfile, const string &filename, shared_ptr p, bool async) override; bool exist(const string &backfile, const string &filename) override; int for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) override; }g_fszip; static class FSTar: public FSBackFile { public: FSTar() {m_ext = ".TAR"; }; int load(const string &backfile, const string &filename, shared_ptr p, bool async) override; bool exist(const string &backfile, const string &filename) override; int for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) override; }g_fstar; static class FSFat : public FSBackFile { public: FSFat() { m_ext = ".SDCARD"; }; int load(const string &backfile, const string &filename, shared_ptr p, bool async) override; bool exist(const string &backfile, const string &filename) override; int for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) override; }g_fsfat; class FSCompressStream : public FSBackFile { public: bool exist(const string &backfile, const string &filename) override; int for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) override; }; static class FSBz2 : public FSCompressStream { public: FSBz2() { m_ext = ".BZ2"; }; int load(const string &backfile, const string &filename, shared_ptr p, bool async) override; }g_fsbz2; static class FSGz : public FSCompressStream { public: FSGz() { m_ext = ".GZ"; }; int load(const string &backfile, const string &filename, shared_ptr p, bool async) override; }g_fsgz; static class FS_DATA { public: vector m_pFs; FS_DATA() { m_pFs.push_back(&g_fsflat); m_pFs.push_back(&g_fszip); m_pFs.push_back(&g_fstar); m_pFs.push_back(&g_fsbz2); m_pFs.push_back(&g_fsfat); m_pFs.push_back(&g_fsgz); m_pFs.push_back(&g_fshttps); m_pFs.push_back(&g_fshttp); } int get_file_timesample(const string &filename, uint64_t *ptimesame) { if (ptimesame == nullptr) { set_last_err_string("ptimesame is null\n"); return -1; } for (int i = 0; i < m_pFs.size(); i++) { if (!m_pFs[i]->get_file_timesample(filename, ptimesame)) return 0; } return -1; } int for_each_ls(uuu_ls_file fn, string path, void *p) { for (int i = m_pFs.size() -1; i >= 0; i--) { string back, filename; if (m_pFs[i]->split(path, &back, &filename, true) == 0) if(m_pFs[i]->for_each_ls(fn, back, filename, p)==0) { return 0; } } return 0; } bool exist(const string &filename) { for (int i = 0; i < m_pFs.size(); i++) { string back, fn; if (m_pFs[i]->split(filename, &back, &fn) == 0) if (m_pFs[i]->exist(back, fn)) return true; } return false; } int load(const string &filename, shared_ptr p, bool async) { for (int i = 0; i < m_pFs.size(); i++) { string back, fn; if (m_pFs[i]->split(filename, &back, &fn) == 0) if(m_pFs[i]->load(back, fn, p, async) == 0) return 0; } string err; err = "fail open file: "; err += filename; set_last_err_string(err); return -1; } }g_fs_data; int FSBackFile::get_file_timesample(const string &filename, uint64_t *ptime) { string back, file; if (split(filename, &back, &file)) return -1; return g_fs_data.get_file_timesample(back, ptime); } bool FSZip::exist(const string &backfile, const string &filename) { Zip zip; if (zip.Open(backfile)) return false; return zip.check_file_exist(filename); } int FSZip::for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) { Zip zip; if (zip.Open(backfile)) return -1; for(auto it = zip.m_filemap.begin(); it!=zip.m_filemap.end(); ++it) { if(it->first.substr(0, filename.size()) == filename || filename.empty()) { string name = backfile; name += "/"; name += it->first; fn(name.c_str()+1, p); } } return 0; } int zip_async_load(string zipfile, string fn, shared_ptr buff) { std::lock_guard lock(buff->m_async_mutex); Zip zip; if (zip.Open(zipfile)) return -1; if(zip.get_file_buff(fn, buff)) return -1; buff->m_avaible_size = buff->m_DataSize; atomic_fetch_or(&buff->m_dataflags, FILEBUFFER_FLAG_LOADED); buff->m_request_cv.notify_all(); return 0; } int FSZip::load(const string &backfile, const string &filename, shared_ptr p, bool async) { Zip zip; if (zip.Open(backfile)) return -1; if (!zip.check_file_exist(filename)) return -1; if (async) { p->m_aync_thread = thread(zip_async_load, backfile, filename, p); } else { if(zip.get_file_buff(filename, p)) return -1; atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); } return 0; } bool FSTar::exist(const string &backfile, const string &filename) { Tar tar; if (tar.Open(backfile)) return false; return tar.check_file_exist(filename); } int FSTar::for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) { Tar tar; if (tar.Open(backfile)) return -1; for(auto it = tar.m_filemap.begin(); it!=tar.m_filemap.end(); ++it) { if(it->first.substr(0, filename.size()) == filename || filename.empty()) { string name = backfile; name += "/"; name += it->first; fn(name.c_str()+1, p); } } return 0; } int FSTar::load(const string &backfile, const string &filename, shared_ptr p, bool async) { Tar tar; if (tar.Open(backfile)) return -1; if (!tar.check_file_exist(filename)) return -1; if(tar.get_file_buff(filename, p)) return -1; p->m_avaible_size = p->m_DataSize; atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); return 0; } bool FSFat::exist(const string &backfile, const string &filename) { Fat fat; if (fat.Open(backfile)) { return false; } return fat.m_filemap.find(filename) != fat.m_filemap.end(); } int FSFat::load(const string &backfile, const string &filename, shared_ptr p, bool async) { Fat fat; if (fat.Open(backfile)) { return -1; } if(fat.get_file_buff(filename, p)) return -1; atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); return 0; } int FSFat::for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) { Fat fat; if (fat.Open(backfile)) { return -1; } for(auto it = fat.m_filemap.begin(); it != fat.m_filemap.end(); ++it) { if(it->first.substr(0, filename.size()) == filename || filename.empty()) { string name = backfile; name += "/"; name += it->first; fn(name.c_str()+1, p); } } return 0; } bool FSCompressStream::exist(const string &backfile, const string &filename) { if (filename == "*") return true; return false; } int FSCompressStream::for_each_ls(uuu_ls_file fn, const string &backfile, const string &filename, void *p) { if(!g_fs_data.exist(backfile)) return -1; string str; str = backfile + "/*"; fn(str.c_str() + 1, p); return 0; } struct bz2_blk { size_t start; size_t size; size_t decompress_offset; size_t decompress_size; size_t actual_size; int error; }; class bz2_blks { public: vector blk; mutex blk_mutex; condition_variable cv; mutex con_mutex; atomic top; atomic bottom; bz2_blks() { top = 0; bottom = ULLONG_MAX; } }; int bz2_update_available(shared_ptr p, bz2_blks * pblk) { lock_guard lock(pblk->blk_mutex); size_t sz = 0; for (int i = 1; i < pblk->blk.size() - 1; i++) { if (pblk->blk[i].error) break; if (!pblk->blk[i].actual_size) break; sz += pblk->blk[i].actual_size; } p->m_avaible_size = sz; p->m_request_cv.notify_all(); return 0; } int bz2_decompress(shared_ptr pbz, shared_ptr p, bz2_blks * pblk) { bz2_blk one; size_t cur; vector buff; while (pblk->top + 1 < pblk->bottom) { if (p->IsError()) return -1; { std::unique_lock lck(pblk->con_mutex); while (pblk->top + 1 >= pblk->blk.size()) { pblk->cv.wait(lck); if (p->IsError()) return -1; } } { lock_guard lock(pblk->blk_mutex); if (pblk->top < pblk->blk.size() - 1) { cur = pblk->top; one = pblk->blk[pblk->top]; pblk->top++; } else { continue; } } unsigned int len = one.decompress_size; buff.resize(len); one.error = BZ2_bzBuffToBuffDecompress((char*)buff.data(), &len, (char*)pbz->data() + one.start, one.size, 0, 0); one.actual_size = len; { lock_guard lock(pblk->blk_mutex); (*pblk).blk[cur] = one; } { lock_guard lock(p->m_data_mutex); if (p->size() < one.decompress_offset + one.actual_size) if(p->resize(one.decompress_offset + one.actual_size)) return -1; memcpy(p->data() + one.decompress_offset, buff.data(), one.actual_size); } bz2_update_available(p, pblk); } return 0; } int bz_async_load(string filename, shared_ptr p) { shared_ptr pbz; pbz = get_file_buffer(filename, true); if (pbz == nullptr) { string err; err = "Failure get file buffer: "; err += filename; set_last_err_string(err); return -1; } bz2_blks blks; bz2_blk one; memset(&one, 0, sizeof(one)); blks.blk.push_back(one); blks.top = 1; size_t total = 0; uint8_t *p1 = &pbz->at(0); int nthread = thread::hardware_concurrency(); vector threads; if (p->reserve(pbz->size() * 5)) //estimate uncompressed memory size; { set_last_err_string("Out of memory"); return -1; } for (int i = 0; i < nthread; i++) { threads.push_back(thread(bz2_decompress, pbz, p, &blks)); #ifdef WIN32 if( i!=0 ) SetThreadPriority(threads[i].native_handle(), THREAD_PRIORITY_BELOW_NORMAL); #endif } size_t requested = 0; for (size_t i = 0; i < pbz->size() - 10; i++) { if(i >= requested) { requested = i + 0x10000; if (requested > pbz->size()) requested = pbz->size(); if (pbz->request_data(requested)) { atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_ERROR_BIT); blks.cv.notify_all(); for (int i = 0; i < nthread; i++) { threads[i].join(); } return -1; } } uint16_t *header = (uint16_t *)p1++; if (*header == 0x5a42) //"BZ" { uint32_t *magic1 = (uint32_t *)&pbz->at(i+4); if (*magic1 == 0x26594131) //PI 3.1415926 { uint16_t *magic2 = (uint16_t *)&pbz->at(i + 8); if (*magic2 == 0x5953) { /*which is valude bz2 header*/ struct bz2_blk one; memset(&one, 0, sizeof(one)); one.start = i; { lock_guard lock(blks.blk_mutex); blks.blk.back().size = i - blks.blk.back().start; one.decompress_offset = blks.blk.back().decompress_offset + blks.blk.back().decompress_size; one.decompress_size = (pbz->at(i + 3) - '0') * 100 * 1000; /* not l024 for bz2 */ blks.blk.push_back(one); } total += one.decompress_size; blks.cv.notify_all(); } } } } if (blks.blk.size() == 1) { set_last_err_string("Can't find validate bz2 magic number"); return -1; } blks.blk.back().size = pbz->size() - blks.blk.back().start; { lock_guard lock(p->m_data_mutex); if(p->resize(total)) return -1; } atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_KNOWN_SIZE); p->m_request_cv.notify_all(); { lock_guard lock(blks.blk_mutex); struct bz2_blk one; memset(&one, 0, sizeof(one)); blks.blk.push_back(one); blks.bottom = blks.blk.size(); blks.cv.notify_all(); } for (int i = 0; i < nthread; i++) { threads[i].join(); } for (int i = 1; i < blks.blk.size(); i++) { if (blks.blk[i].error) { set_last_err_string("decompress err"); return -1; } if ((blks.blk[i].decompress_size != blks.blk[i].actual_size) && (i != blks.blk.size() - 2)) /*two dummy blks (one header and other end)*/ { set_last_err_string("bz2: only support last block less then other block"); return -1; } } bz2_update_available(p, &blks); if(p->resize(p->m_avaible_size)) return -1; atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); return 0; } bool is_pbzip2_file(string filename) { shared_ptr file=get_file_buffer(filename, true); uint64_t filesize= file->size(); uint64_t readsize= (filesize< (1024*1024) )? filesize:(1024*1024); //read at most 1MB, because maximum block size is 900kb file->request_data(readsize); int header_num=0; uint8_t* ptr= file->data(); for(size_t i =0 ; i < readsize ; i++) { if(ptr[0]=='B'&& ptr[1]=='Z'&& ptr[2]=='h' && ptr[4]=='1'&& ptr[5]=='A' && ptr[6]=='Y' && ptr[7]=='&' && ptr[8]=='S'&& ptr[9]=='Y') { header_num++; } ptr++; } if(header_num>1) return true; else return false; } int decompress_single_thread(string name,shared_ptrp) { uint8_t* decompressed_file; uint64_t decompressed_size; uint8_t* compressed_file; uint64_t compressed_size; shared_ptr filebuffer=get_file_buffer(name); compressed_file=filebuffer->data(); compressed_size=filebuffer->size(); decompressed_file=p->data(); decompressed_size=0; p->reserve(7*compressed_size);//the usual compressed ratio is about 18%, so 7*18% > 100% bz_stream strm; strm.bzalloc = nullptr; strm.bzfree = nullptr; strm.opaque = nullptr; int ret; ret = BZ2_bzDecompressInit (&strm,0, 0 ); if (ret != BZ_OK) return -1; strm.next_in = (char*)compressed_file; strm.avail_in = compressed_size; uint64_t decompress_amount=5000; //decompress 5000 byte every iteration, choose 5000 only because the pbzip2 also used 5000 in their implementation. while(1) { p->reserve(decompressed_size+1000*decompress_amount);//make sure the space is enough,multiple by 1000 to avoid repeated realloc strm.next_out=(char*)p->data()+decompressed_size; strm.avail_out=decompress_amount; ret=BZ2_bzDecompress(&strm); decompressed_size+=decompress_amount; if(ret==BZ_STREAM_END) { decompressed_size-= strm.avail_out; break; } else if (ret != BZ_OK)//if it is not bz_ok nor bz_stream_end, decompression failed. return -1; } p->resize(decompressed_size); BZ2_bzDecompressEnd(&strm); atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); return 0; } int FSBz2::load(const string &backfile, const string &filename, shared_ptrp, bool async) { if (!g_fs_data.exist(backfile)) { string str; str = "Failure open file:"; str += backfile; set_last_err_string(str); return -1; } if (filename != "*") { string star ("/*"); string decompressed_name= backfile+ star; shared_ptr decompressed_file=get_file_buffer(decompressed_name); Tar tar; tar.Open(decompressed_name); if (tar.get_file_buff(filename, p)) return -1; p->m_avaible_size = p->m_DataSize; } else { if(!check_file_exist(backfile.substr(1))) return -1; if(is_pbzip2_file(backfile.substr(1))==true)//the bz2 file can be decompressed with multithreading p->m_aync_thread = thread(bz_async_load, backfile, p); else//the bz2 file can only be decompressed using single thread p->m_aync_thread = thread(decompress_single_thread, backfile, p); if (!async) { p->m_aync_thread.join(); if (! p->IsLoaded()) { set_last_err_string("async data load failure\n"); return -1; } } } return 0; } int FSGz::load(const string &backfile, const string &filename, shared_ptrp, bool async) { if (!g_fs_data.exist(backfile)) { string str; str = "Failure open file:"; str += backfile; set_last_err_string(str); return -1; } if (filename != "*") { string star("/*"); string decompressed_name = backfile + star; shared_ptr decompressed_file = get_file_buffer(decompressed_name); Tar tar; tar.Open(decompressed_name); if (tar.get_file_buff(filename, p)) return -1; p->m_avaible_size = p->m_DataSize; } else { gzFile fp = gzopen(backfile.c_str() + 1, "r"); if (fp == nullptr) { set_last_err_string("Open file failure"); return -1; } shared_ptr pb = get_file_buffer(backfile); p->reserve(pb->size() * 4); /* guest uncompress size */ size_t sz = 0x100000; if (sz > pb->size() * 4) sz = p->size(); uuu_notify ut; ut.type = uuu_notify::NOTIFY_DECOMPRESS_START; ut.str = (char*)backfile.c_str(); call_notify(ut); ut.type = uuu_notify::NOTIFY_DECOMPRESS_SIZE; ut.total = pb->size(); call_notify(ut); size_t cur = 0; while (!gzeof(fp)) { size_t ret = gzread(fp, p->data() + cur, sz); if (sz < 0) { set_last_err_string("decompress error"); return -1; } cur += ret; p->reserve(cur + sz); ut.type = uuu_notify::NOTIFY_DECOMPRESS_POS; ut.index = gzoffset(fp); call_notify(ut); } p->resize(cur); p->m_avaible_size = cur; ut.type = uuu_notify::NOTIFY_DECOMPRESS_POS; ut.index = pb->size(); call_notify(ut); gzclose(fp); atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); } return 0; } uint64_t get_file_timesample(string filename) { uint64_t time=0; g_fs_data.get_file_timesample(filename, &time); return time; } shared_ptr get_file_buffer(string filename, bool async) { filename = remove_quota(filename); if (!filename.empty() && filename[0] != MAGIC_PATH) { if (filename == "..") filename = g_current_dir.substr(0, g_current_dir.size() - 1); else filename = g_current_dir + filename; } string_ex path; path += filename; path.replace('\\', '/'); filename = path; bool find; { std::lock_guard lock(g_mutex_map); find = (g_filebuffer_map.find(filename) == g_filebuffer_map.end()); } if (find) { shared_ptr p(new FileBuffer); if (p->reload(filename, async)) return nullptr; { std::lock_guard lock(g_mutex_map); g_filebuffer_map[filename] = p; } return p; } else { shared_ptr p; { std::lock_guard lock(g_mutex_map); p= g_filebuffer_map[filename]; } if (p->m_timesample != get_file_timesample(filename)) if (p->reload(filename, async)) { return nullptr; } if (!p->IsLoaded() && !async) { std::lock_guard lock(p->m_async_mutex); if(p->m_aync_thread.joinable()) p->m_aync_thread.join(); if(!p->IsLoaded()) { return nullptr; } } return p; } } FileBuffer::FileBuffer() { m_pDatabuffer = nullptr; m_DataSize = 0; m_MemSize = 0; m_dataflags = 0; m_avaible_size = 0; } FileBuffer::FileBuffer(void *p, size_t sz) { m_pDatabuffer = nullptr; m_DataSize = 0; m_MemSize = 0; m_pDatabuffer = (uint8_t*)malloc(sz); m_MemSize = m_DataSize = sz; memcpy(m_pDatabuffer, p, sz); m_dataflags = 0; } FileBuffer::~FileBuffer() { if(m_aync_thread.joinable()) m_aync_thread.join(); if (m_pDatabuffer) { if(m_allocate_way == ALLOCATION_WAYS::MMAP) unmapfile(); if(m_allocate_way == ALLOCATION_WAYS::MALLOC) free(m_pDatabuffer); } } int FileBuffer::mapfile(string filename, size_t sz) { #ifdef _MSC_VER m_Request.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION; m_Request.StructureLength = sizeof(REQUEST_OPLOCK_INPUT_BUFFER); m_Request.RequestedOplockLevel = (OPLOCK_LEVEL_CACHE_READ | OPLOCK_LEVEL_CACHE_HANDLE); m_Request.Flags = REQUEST_OPLOCK_INPUT_FLAG_REQUEST; REQUEST_OPLOCK_OUTPUT_BUFFER Response; m_OverLapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); ResetEvent(m_OverLapped.hEvent); m_file_handle = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, nullptr); if (m_file_handle == INVALID_HANDLE_VALUE) { string err = "Create File Failure "; err += filename; set_last_err_string(err); return -1; } BOOL bSuccess = DeviceIoControl(m_file_handle, FSCTL_REQUEST_OPLOCK, &m_Request, sizeof(m_Request), &Response, sizeof(Response), nullptr, &m_OverLapped); if (bSuccess || GetLastError() == ERROR_IO_PENDING) { m_file_monitor = thread(file_overwrite_monitor, filename, this); } m_file_map = CreateFileMapping(m_file_handle, nullptr, PAGE_READONLY, 0, 0, nullptr); if (m_file_map == INVALID_HANDLE_VALUE) { set_last_err_string("Fail create Map"); return -1; } m_pDatabuffer = (uint8_t *)MapViewOfFile(m_file_map, FILE_MAP_READ, 0, 0, sz); m_DataSize = sz; m_MemSize = sz; m_allocate_way = ALLOCATION_WAYS::MMAP; #else int fd = open(filename.c_str(), O_RDONLY); if (fd == -1) { string err; err += "xx Failure open file: "; err + filename; set_last_err_string(err); return -1; } m_pDatabuffer = (uint8_t *)mmap64(0, sz, PROT_READ, MAP_SHARED, fd, 0); if (m_pDatabuffer == MAP_FAILED) { m_pDatabuffer = nullptr; set_last_err_string("mmap failure\n"); return -1; } m_DataSize = sz; m_MemSize = sz; m_allocate_way = ALLOCATION_WAYS::MMAP; close(fd); #endif if (m_pDatabuffer) return 0; set_last_err_string("mmap file failure"); return -1; } int FileBuffer::ref_other_buffer(shared_ptr p, size_t offset, size_t size) { m_pDatabuffer = p->data() + offset; m_DataSize = m_MemSize = size; m_avaible_size = m_DataSize; m_allocate_way = ALLOCATION_WAYS::REF; m_ref = p; return 0; } int FileBuffer::reload(string filename, bool async) { atomic_init(&this->m_dataflags, 0); if (g_fs_data.load(filename, shared_from_this(), async) == 0) { m_timesample = get_file_timesample(filename); return 0; } return -1; } int FileBuffer::request_data(size_t sz) { std::unique_lock lck(m_requext_cv_mutex); while(!(this->m_dataflags & FILEBUFFER_FLAG_KNOWN_SIZE_BIT)) m_request_cv.wait(lck); if (IsLoaded()) { if (sz > this->size()) { set_last_err_string("exceed data size"); return -1; } } while ((sz > m_avaible_size) && !IsLoaded()) { if (IsError()) { set_last_err_string("Async request data error"); return -1; } m_request_cv.wait(lck); } if (IsLoaded()) { if (sz > m_avaible_size) { set_last_err_string("request offset execeed memory size"); return -1; } } return 0; } int FileBuffer::request_data(std::vector &data, size_t offset, size_t sz) { int64_t ret; ret = request_data(data.data(), offset, sz); if (ret < 0) { data.clear(); return -1; } data.resize(ret); return 0; } int64_t FileBuffer::request_data(void *data, size_t offset, size_t sz) { bool needlock = false; int ret = 0; if (IsLoaded()) { if (offset >= this->size()) { set_last_err_string("request offset execeed memory size"); return -1; } } else { std::unique_lock lck(m_requext_cv_mutex); while ((offset + sz > m_avaible_size) && !IsLoaded()) { if (IsError()) { set_last_err_string("Async request data error"); return -1; } m_request_cv.wait(lck); } if (IsLoaded()) { if (offset > m_avaible_size) { set_last_err_string("request offset execeed memory size"); return -1; } } needlock = true; } size_t size = sz; if (offset + size >= m_avaible_size) size = m_avaible_size - offset; if (needlock) m_data_mutex.lock(); if (this->data()) { memcpy(data, this->data() + offset, size); ret = size; } else { set_last_err_string("Out of memory"); ret = ERR_OUT_MEMORY; } if (needlock) m_data_mutex.unlock(); return ret; } std::shared_ptr FileBuffer::request_data(size_t offset, size_t sz) { shared_ptr p(new FileBuffer); if (IsLoaded()) { if (offset >= this->size()) { set_last_err_string("request offset bigger than file size"); return nullptr; } size_t size = sz; if (offset + sz > this->size()) size = this->size() - offset; p->ref_other_buffer(shared_from_this(), offset, size); return p; } p->reserve(sz); int64_t ret = request_data(p->m_pDatabuffer, offset, sz); if (ret < 0) return nullptr; p->resize(ret); p->m_avaible_size = ret; atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); return p; } int FileBuffer::reserve(size_t sz) { assert(m_allocate_way == ALLOCATION_WAYS::MALLOC); if (sz > m_MemSize) { m_pDatabuffer = (uint8_t*)realloc(m_pDatabuffer, sz); m_MemSize = sz; if (m_pDatabuffer == nullptr) { set_last_err_string("Out of memory\n"); return -1; } } return 0; } int FileBuffer::resize(size_t sz) { if (this->m_allocate_way == ALLOCATION_WAYS::REF) { if (sz > m_DataSize) { assert(true); return 0; } m_DataSize = sz; return m_DataSize; } int ret = reserve(sz); m_DataSize = sz; return ret; } int FileBuffer::swap(FileBuffer &a) { std::swap(m_pDatabuffer, a.m_pDatabuffer); std::swap(m_DataSize, a.m_DataSize); std::swap(m_MemSize, a.m_MemSize); std::swap(m_allocate_way, a.m_allocate_way); return 0; } int FileBuffer::unmapfile() { if (m_pDatabuffer) { #ifdef _MSC_VER UnmapViewOfFile(m_pDatabuffer); m_pDatabuffer = nullptr; CloseHandle(m_file_map); CloseHandle(m_file_handle); SetEvent(m_OverLapped.hEvent); if (m_file_monitor.joinable()) m_file_monitor.join(); CloseHandle(m_OverLapped.hEvent); m_OverLapped.hEvent = m_file_map = m_file_handle = INVALID_HANDLE_VALUE; #else munmap(m_pDatabuffer, m_DataSize); #endif m_pDatabuffer = nullptr; } return 0; } bool check_file_exist(string filename, bool start_async_load) { return get_file_buffer(filename, true) != nullptr; } #ifdef WIN32 int file_overwrite_monitor(string filename, FileBuffer *p) { WaitForSingleObject(p->m_OverLapped.hEvent, INFINITE); string str; str = ">"; str += filename; if(p->m_pDatabuffer && p->get_m_allocate_way() == FileBuffer::ALLOCATION_WAYS::MMAP) { std::lock_guard lock(g_mutex_map); p->m_file_monitor.detach(); /*Detach itself, erase will delete p*/ if(g_filebuffer_map.find(str) != g_filebuffer_map.end()) g_filebuffer_map.erase(str); } return 0; } #endif int uuu_for_each_ls_file(uuu_ls_file fn, const char *file_path, void *p) { string_ex path; path +=">"; string f = file_path; if(f.size() == 0) { path += "./"; }else if( f[0] == '/') { path += "//"; }else { path += "./"; } path+=file_path; path.replace('\\', '/'); f = path; return g_fs_data.for_each_ls(fn, f, p); } mfgtools-uuu_1.4.193/libuuu/buffer.h000066400000000000000000000106011417203213400173430ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include #include #include #include #include #include #include #ifdef _MSC_VER #include #else #include #include #include #endif #ifdef __APPLE__ #define mmap64 mmap #endif #ifdef WIN32 class FileBuffer; int file_overwrite_monitor(std::string filename, FileBuffer *p); #endif //bit 0, data loaded //bit 1, data total size known #define FILEBUFFER_FLAG_LOADED_BIT 0x1 #define FILEBUFFER_FLAG_KNOWN_SIZE_BIT 0x2 #define FILEBUFFER_FLAG_ERROR_BIT 0x4 #define FILEBUFFER_FLAG_LOADED (FILEBUFFER_FLAG_LOADED_BIT|FILEBUFFER_FLAG_KNOWN_SIZE_BIT) // LOADED must be knownsize #define FILEBUFFER_FLAG_KNOWN_SIZE FILEBUFFER_FLAG_KNOWN_SIZE_BIT class FileBuffer: public std::enable_shared_from_this { public: enum class ALLOCATION_WAYS { MALLOC, MMAP, REF, VMALLOC, }; std::mutex m_data_mutex; uint8_t *m_pDatabuffer; size_t m_DataSize; size_t m_MemSize; std::shared_ptr m_ref; int ref_other_buffer(std::shared_ptr p, size_t offset, size_t size); std::mutex m_async_mutex; std::atomic_int m_dataflags; std::thread m_aync_thread; std::atomic_size_t m_avaible_size; std::condition_variable m_request_cv; std::mutex m_requext_cv_mutex; #ifdef WIN32 OVERLAPPED m_OverLapped; REQUEST_OPLOCK_INPUT_BUFFER m_Request; HANDLE m_file_handle; HANDLE m_file_map; std::thread m_file_monitor; #endif FileBuffer(); FileBuffer(void*p, size_t sz); ~FileBuffer(); ALLOCATION_WAYS get_m_allocate_way() const noexcept { return m_allocate_way; } int64_t request_data(void * data, size_t offset, size_t sz); int request_data(std::vector &data, size_t offset, size_t sz); int request_data(size_t total); std::shared_ptr request_data(size_t offset, size_t sz); bool IsLoaded() const noexcept { return m_dataflags & FILEBUFFER_FLAG_LOADED_BIT; } bool IsKnownSize() const noexcept { return m_dataflags & FILEBUFFER_FLAG_KNOWN_SIZE_BIT; } bool IsError() const noexcept { return m_dataflags & FILEBUFFER_FLAG_ERROR_BIT; } uint8_t * data() noexcept { return m_pDatabuffer ; } size_t size() const noexcept { return m_DataSize; } uint8_t & operator[] (size_t index) { assert(m_pDatabuffer); assert(index < m_DataSize); return *(m_pDatabuffer + index); } uint8_t & at(size_t index) { return (*this)[index]; } int resize(size_t sz); int reserve(size_t sz); int swap(FileBuffer & a); int mapfile(std::string filename, size_t sz); int unmapfile(); //Read write lock; uint64_t m_timesample; int reload(std::string filename, bool async=false); private: ALLOCATION_WAYS m_allocate_way = ALLOCATION_WAYS::MALLOC; }; std::shared_ptr get_file_buffer(std::string filename, bool aysnc=false); bool check_file_exist(std::string filename, bool start_async_load=true); void set_current_dir(const std::string &dir); mfgtools-uuu_1.4.193/libuuu/cmd.cpp000066400000000000000000000571751417203213400172110ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include "cmd.h" #include "libcomm.h" #include "liberror.h" #include "libuuu.h" #include "config.h" #include "trans.h" #include "sdps.h" #include #include "buffer.h" #include "sdp.h" #include "fastboot.h" #include #include #include #include static CmdMap g_cmd_map; static CmdObjCreateMap g_cmd_create_map; static string g_cmd_list_file; static map> g_environment; int insert_env_variable(string key, string value) { g_environment[std::this_thread::get_id()][key] = value; return 0; } string get_env_variable(string key) { return g_environment[std::this_thread::get_id()][key]; } int clear_env() { return g_environment.erase(std::this_thread::get_id()); } bool is_env_exist(string key) { return g_environment[std::this_thread::get_id()].find(key) != g_environment[std::this_thread::get_id()].end(); } int get_string_in_square_brackets(const std::string &cmd, std::string &context); int parser_cmd_list_file(shared_ptr pbuff, CmdMap *pCmdMap = nullptr); std::string remove_square_brackets(const std::string &cmd); template void * create_object() { return new T; } typedef void * (*FN)(); FN g_fn = create_object; CmdCtx::~CmdCtx() { } CmdBase::~CmdBase() { } int CmdBase::parser(char *p) { if (p != nullptr) m_cmd = p; size_t pos = 0; string param = get_next_param(m_cmd, pos); if (param.find(':') != string::npos) param = get_next_param(m_cmd, pos); int index = 0; while (pos < m_cmd.size()) { param = get_next_param(m_cmd, pos); struct Param *pp = nullptr; if (m_NoKeyParam) { if (index > m_param.size()) { set_last_err_string("More parameter then expected"); return -1; } pp = &(m_param[index]); index++; } else { for (size_t i = 0; i < m_param.size(); i++) { string key = string(m_param[i].key); if (compare_str(param, key, m_param[i].ignore_case)) { pp = &(m_param[i]); break; } } } if (pp == nullptr) { string err; err = "unknown Option"; err += param; set_last_err_string(err); return -1; } if (pp->type == Param::Type::e_uint32) { if (!m_NoKeyParam) param = get_next_param(m_cmd, pos); *(uint32_t*)pp->pData = str_to_uint32(param); } if (pp->type == Param::Type::e_uint64) { if (!m_NoKeyParam) param = get_next_param(m_cmd, pos); *(uint64_t*)pp->pData = str_to_uint64(param); } if (pp->type == Param::Type::e_string_filename) { if (!m_NoKeyParam) param = get_next_param(m_cmd, pos); *(string*)pp->pData = param; if (!check_file_exist(param)) return -1; } if (pp->type == Param::Type::e_string) { if (!m_NoKeyParam) param = get_next_param(m_cmd, pos); *(string*)pp->pData = param; } if (pp->type == Param::Type::e_bool) { *(bool*)pp->pData = true; } if (pp->type == Param::Type::e_null) { } } if (m_bCheckTotalParam) { if (index < m_param.size()) { string str; str += "Missed: "; str += m_param[index].Error; set_last_err_string(str); return -1; } } return 0; } int CmdBase::parser_protocal(char *p, size_t &pos) { if (p) m_cmd = *p; string prot = get_next_param(m_cmd, pos, ':'); string param; if (get_string_in_square_brackets(prot, param)) return -1; if (!param.empty()) { size_t param_pos = 0; string s = get_next_param(param, param_pos); if (s == "-t") { string timeout; timeout = get_next_param(param, param_pos); m_timeout = str_to_uint32(timeout); } else { string err; err = "Unknown option: "; err += s; err += " for protocol: "; err += remove_square_brackets(prot); set_last_err_string(err); return -1; } } return 0; } int CmdBase::dump() { uuu_notify nt; nt.type = uuu_notify::NOTIFY_CMD_INFO; string str = m_cmd; str += "\n"; nt.str = (char*)str.c_str(); call_notify(nt); return 0; } int CmdList::run_all(CmdCtx *p, bool dry) { CmdList::iterator it; int ret; uuu_notify nt; nt.type = uuu_notify::NOTIFY_CMD_TOTAL; nt.total = size(); call_notify(nt); int i = 0; for (it = begin(); it != end(); it++, i++) { uuu_notify nt; nt.type = uuu_notify::NOTIFY_CMD_INDEX; nt.index = i; call_notify(nt); nt.type = uuu_notify::NOTIFY_CMD_START; nt.str = (char *)(*it)->get_cmd().c_str(); call_notify(nt); if (dry) ret = (*it)->dump(); else ret = (*it)->run(p); nt.type = uuu_notify::NOTIFY_CMD_END; nt.status = ret; call_notify(nt); if (ret) return ret; if ((*it)->get_lastcmd()) break; } return ret; } int CmdMap::run_all(const std::string &protocol, CmdCtx *p, bool dry_run) { if (find(protocol) == end()) { set_last_err_id(-1); std::string err; err.append("Unknown Protocol:"); err.append(protocol); set_last_err_string(err); return -1; } return at(protocol)->run_all(p, dry_run); } string get_next_param(const string &cmd, size_t &pos, char sperate) { string str; if (pos == string::npos) return str; if (pos >= cmd.size()) return str; //trim left space while (cmd[pos] == sperate && pos < cmd.size()) pos++; bool quate = false; size_t end = string::npos; for (size_t s = pos; s < cmd.size(); s++) { if (cmd[s] == '"') quate = !quate; if (!quate && cmd[s] == sperate) { end = s; break; } } if (end == cmd.npos) end = cmd.size(); str = cmd.substr(pos, end - pos); pos = end + 1; return str; } string remove_square_brackets(const string &cmd) { size_t sz=cmd.find('['); return cmd.substr(0, sz); } int get_string_in_square_brackets(const string &cmd, string &context) { size_t start = cmd.find('['); if (start == string::npos) { context.clear(); return 0; } size_t end = cmd.find(']', start); if (end == string::npos) { set_last_err_string("missed ]"); return -1; } context = cmd.substr(start + 1, end - start - 1); return 0; } template T str_to_uint(const std::string &str, bool * conversion_succeeded) { if (conversion_succeeded) *conversion_succeeded = false; int base = 10; if (str.size() > 2) { if (str.substr(0, 2).compare("0x") == 0) { base = 16; } } try { const auto tmp_val = std::stoull(str, nullptr, base); if (tmp_val <= MAX_VAL) { if (conversion_succeeded) *conversion_succeeded = true; return static_cast(tmp_val); } } catch (const std::invalid_argument &) { } catch (const std::out_of_range &) { } set_last_err_string("Conversion of string to unsigned failed"); return MAX_VAL; } uint16_t str_to_uint16(const string &str, bool * conversion_suceeded) { return str_to_uint(str, conversion_suceeded); } uint32_t str_to_uint32(const string &str, bool * conversion_suceeded) { return str_to_uint(str, conversion_suceeded); } uint64_t str_to_uint64(const string &str, bool * conversion_suceeded) { return str_to_uint(str, conversion_suceeded); } template shared_ptr new_cmd_obj(char *p) { return shared_ptr(new T(p)); } CmdObjCreateMap::CmdObjCreateMap() { (*this)["CFG:"] = new_cmd_obj; (*this)["SDPS:BOOT"] = new_cmd_obj; (*this)["SDP:DCD"] = new_cmd_obj; (*this)["SDP:JUMP"] = new_cmd_obj; (*this)["SDP:RDMEM"] = new_cmd_obj; (*this)["SDP:WRMEM"] = new_cmd_obj; (*this)["SDP:WRITE"] = new_cmd_obj; (*this)["SDP:STATUS"] = new_cmd_obj; (*this)["SDP:BOOT"] = new_cmd_obj; (*this)["SDP:BLOG"] = new_cmd_obj; (*this)["SDPU:JUMP"] = new_cmd_obj; (*this)["SDPU:WRITE"] = new_cmd_obj; (*this)["SDPU:BLOG"] = new_cmd_obj; (*this)["SDPV:JUMP"] = new_cmd_obj; (*this)["SDPV:WRITE"] = new_cmd_obj; (*this)["SDPV:BLOG"] = new_cmd_obj; (*this)["FB:GETVAR"] = new_cmd_obj; (*this)["FASTBOOT:GETVAR"] = new_cmd_obj; (*this)["FB:UCMD"] = new_cmd_obj; (*this)["FASTBOOT:UCMD"] = new_cmd_obj; (*this)["FB:ACMD"] = new_cmd_obj; (*this)["FASTBOOT:ACMD"] = new_cmd_obj; (*this)["FB:DOWNLOAD"] = new_cmd_obj; (*this)["FASTBOOT:DOWNLOAD"] = new_cmd_obj; (*this)["FB:UPLOAD"] = new_cmd_obj; (*this)["FASTBOOT:UPLOAD"] = new_cmd_obj; (*this)["FB:FLASH"] = new_cmd_obj; (*this)["FASTBOOT:FLASH"] = new_cmd_obj; (*this)["FB:ERASE"] = new_cmd_obj; (*this)["FASTBOOT:ERASE"] = new_cmd_obj; (*this)["FB:REBOOT"] = new_cmd_obj; (*this)["FASTBOOT:REBOOT"] = new_cmd_obj; (*this)["FB:OEM"] = new_cmd_obj; (*this)["FASTBOOT:OEM"] = new_cmd_obj; (*this)["FB:FLASHING"] = new_cmd_obj; (*this)["FASTBOOT:FLASHING"] = new_cmd_obj; (*this)["FB:SET_ACTIVE"] = new_cmd_obj; (*this)["FASTBOOT:SET_ACTIVE"] = new_cmd_obj; (*this)["FB:CONTINUE"] = new_cmd_obj; (*this)["FASTBOOT:CONTINUE"] = new_cmd_obj; (*this)["FB:UPDATE-SUPER"] = new_cmd_obj; (*this)["FASTBOOT:UPDATE-SUPER"] = new_cmd_obj; (*this)["FB:CREATE-LOGICAL-PARTITION"] = new_cmd_obj; (*this)["FASTBOOT:CREATE-LOGICAL-PARTITION"] = new_cmd_obj; (*this)["FB:DELETE-LOGICAL-PARTITION"] = new_cmd_obj; (*this)["FASTBOOT:DELETE-LOGICAL-PARTITION"] = new_cmd_obj; (*this)["FB:RESIZE-LOGICAL-PARTITION"] = new_cmd_obj; (*this)["FASTBOOT:RESIZE-LOGICAL-PARTITION"] = new_cmd_obj; (*this)["FBK:UCMD"] = new_cmd_obj; (*this)["FBK:ACMD"] = new_cmd_obj; (*this)["FBK:SYNC"] = new_cmd_obj; (*this)["FBK:UCP"] = new_cmd_obj; (*this)["_ALL:DONE"] = new_cmd_obj; (*this)["_ALL:DELAY"] = new_cmd_obj; (*this)["_ALL:SH"] = new_cmd_obj; (*this)["_ALL:SHELL"] = new_cmd_obj; (*this)["_ALL:<"] = new_cmd_obj; (*this)["_ALL:@"] = new_cmd_obj; (*this)["_ALL:ERROR"] = new_cmd_obj; (*this)["_ALL:IF"] = new_cmd_obj; } shared_ptr create_cmd_obj(string cmd) { string param; size_t pos = 0; param = get_next_param(cmd, pos, ':'); param = remove_square_brackets(param); param += ":"; param = str_to_upper(param); if (g_cmd_create_map.find(param) == g_cmd_create_map.end()) { string s = param; param = get_next_param(cmd, pos); s += str_to_upper(param); if (g_cmd_create_map.find(s) != g_cmd_create_map.end()) return g_cmd_create_map[s]((char*)cmd.c_str()); string commoncmd = "_ALL:"; commoncmd += str_to_upper(param); if (g_cmd_create_map.find(commoncmd) != g_cmd_create_map.end()) return g_cmd_create_map[commoncmd]((char*)cmd.c_str()); } else { return g_cmd_create_map[param]((char*)cmd.c_str()); } string err; err = "Unknown Command:"; err += cmd; set_last_err_string(err); return nullptr; } int uuu_run_cmd(const char * cmd, int dry) { return run_cmd(nullptr, cmd, dry); } int run_cmd(CmdCtx *pCtx, const char * cmd, int dry) { shared_ptr p; p = create_cmd_obj(cmd); int ret; if (p == nullptr) return -1; uuu_notify nt; nt.type = uuu_notify::NOTIFY_CMD_TOTAL; nt.total = 1; call_notify(nt); nt.type = uuu_notify::NOTIFY_CMD_START; nt.str = (char *)p->get_cmd().c_str(); call_notify(nt); if (typeid(*p) != typeid(CfgCmd)) { size_t pos = 0; string c = cmd; string pro = get_next_param(c, pos, ':'); pro = remove_square_brackets(pro); pro += ":"; if (p->parser()) ret = -1; else { if (dry) { ret = p->dump(); }else { CmdUsbCtx ctx; if (pCtx == nullptr) { ret = ctx.look_for_match_device(pro.c_str()); if (ret) return ret; pCtx = &ctx; } ret = p->run(pCtx); } } } else { return ret = dry? p->dump() : p->run(nullptr); } nt.type = uuu_notify::NOTIFY_CMD_END; nt.status = ret; call_notify(nt); return ret; } int CmdDone::run(CmdCtx *) { uuu_notify nt; nt.type = uuu_notify::NOTIFY_DONE; call_notify(nt); return 0; } int CmdDelay::parser(char * /*p*/) { size_t pos = 0; string param = get_next_param(m_cmd, pos); if (param.find(':') != string::npos) param = get_next_param(m_cmd, pos); if (str_to_upper(param) != "DELAY") { string err = "Unknown Command:"; err += param; set_last_err_string(err); return -1; } string ms = get_next_param(m_cmd, pos); m_ms = str_to_uint32(ms); return 0; } int CmdDelay::run(CmdCtx *) { std::this_thread::sleep_for(std::chrono::milliseconds(m_ms)); return 0; } int CmdError::parser(char *p) { if (p) m_cmd = p; size_t pos = 0; string s; if (parser_protocal(p, pos)) return -1; s = get_next_param(m_cmd, pos); m_error = m_cmd.substr(pos); return 0; } int CmdError::run(CmdCtx *pCtx) { set_last_err_string(m_error); return -1; } int CmdShell::parser(char * p) { if (p) m_cmd = p; size_t pos = 0; string s; if (parser_protocal(p, pos)) return -1; m_protocal = m_cmd.substr(0, pos); s = get_next_param(m_cmd, pos); m_dyn = (s == "<"); if (pos != string::npos && pos < m_cmd.size()) m_shellcmd = m_cmd.substr(pos); return 0; } int CmdShell::run(CmdCtx*pCtx) { #ifndef WIN32 #define _popen popen #define _pclose pclose #endif FILE *pipe = _popen(m_shellcmd.c_str(), "r"); if (pipe == nullptr) { string err = "failure popen: "; err += m_shellcmd.c_str(); set_last_err_string(err); return -1; } string str; str.resize(256); while (fgets((char*)str.c_str(), str.size(), pipe)) { if (m_dyn) { string cmd; cmd = m_protocal; str.resize(strlen(str.c_str())); cmd += ' '; cmd += str; size_t pos = cmd.find_first_of("\r\n"); if (pos != string::npos) cmd = cmd.substr(0, pos); return run_cmd(pCtx, cmd.c_str(), 0); } uuu_notify nt; nt.type = uuu_notify::NOTIFY_CMD_INFO; nt.str = (char*)str.c_str(); call_notify(nt); } /* Close pipe and print return value of pPipe. */ if (feof(pipe)) { int ret = _pclose(pipe); string_ex str; str.format("\nProcess returned %d\n", ret);; if (ret) { set_last_err_string(str.c_str()); return ret; } } else { set_last_err_string("Error: Failed to read the end of the pipe.\n"); return -1; } return 0; } int CmdEnv::parser(char *p) { if (p) m_cmd = p; size_t pos = 0; if (parser_protocal(p, pos)) return -1; if (pos == string::npos || pos >= m_cmd.size()) return -1; m_unfold_cmd = m_cmd.substr(0, pos); m_unfold_cmd.append(" "); // read the '@' get_next_param(m_cmd, pos); auto cmd = m_cmd.substr(pos); regex expr { "@[0-9a-zA-Z_]+@" }; smatch result; auto last_pos = static_cast(cmd).begin(); auto cmd_end = static_cast(cmd).end(); while (regex_search(last_pos, cmd_end, result, expr)) { for (auto &i : result) { string key { i.first + 1, i.second - 1 }; auto value = [&key]() -> pair { #ifndef WIN32 auto ptr = getenv(key.c_str()); if (ptr) return {true, ptr}; return {false, {}}; #else size_t len; getenv_s(&len, nullptr, 0, key.c_str()); if (!len) return {false, {}}; string value(len-1, '\0'); getenv_s(&len, &value[0], len, key.c_str()); return {true, value}; #endif }(); if (!value.first) { set_last_err_string("variable '" + key + "' is not defined"); return -1; } auto begin = value.second.begin(); auto end = value.second.end(); auto pos = find_if(begin, end, [](char c){ return c == '\r' || c == '\n'; }); m_unfold_cmd.append(&*last_pos, distance(last_pos, i.first)); m_unfold_cmd.append(begin, pos); last_pos = i.second; } } m_unfold_cmd.append(&*last_pos); return 0; } int CmdIf::parser(char *p) { if (p) m_cmd = p; string s; size_t pos = 0; if (parser_protocal(p, pos)) return -1; m_protocal = m_cmd.substr(0, pos); if (pos == string::npos || pos >= m_cmd.size()) return -1; s = get_next_param(m_cmd, pos); if (str_to_upper(s) != "IF") { string err = "Unknown command: "; err += s; set_last_err_string(s); return -1; } size_t lc = pos; get_next_param(m_cmd, pos); int end = m_cmd.find("then", pos); if (end == string::npos) { set_last_err_string("missed key word: then"); return -1; } m_condtion = m_cmd.substr(lc, end - lc); m_true_cmd = m_cmd.substr(end + 4); return 0; } void CmdIf::build_map(CmdCtx*p) { string_ex s; s.format("0x%04X", p->m_config_item->m_vid); insert_env_variable("@VID@", s); s.format("0x%04X", p->m_config_item->m_pid); insert_env_variable("@PID@", s); s.format("0x%04X", p->m_current_bcd); insert_env_variable("@BCD@", s); insert_env_variable("@CHIP@", p->m_config_item->m_chip); } int CmdIf::run(CmdCtx *p) { string l, r; string cmp[] = { "==", "!=", "" }; int i = 0; for (i = 0; !cmp[i].empty(); i++) { size_t pos = m_condtion.find(cmp[i], 0); if (pos != string::npos) { l = m_condtion.substr(0, pos); r = m_condtion.substr(pos + cmp[i].size() + 1); break; } } l = str_to_upper(trim(l)); r = str_to_upper(trim(r)); build_map(p); if (is_env_exist(l)) l = get_env_variable(l); if (is_env_exist(r)) r = get_env_variable(r); switch (i) { case 0: // == if (l != r) return 0; break; case 1: // != if (l == r) return 0; break; default: set_last_err_string("unknown if condition"); return -1; } //Pass condition check; string cmd = m_protocal; cmd += ' '; cmd += this->m_true_cmd; return run_cmd(p, cmd.c_str(), 0); } int CmdEnv::run(CmdCtx *p) { return run_cmd(p, m_unfold_cmd.c_str(), 0); } int run_cmds(const char *procotal, CmdCtx *p) { CmdMap cmdmap, *pCmdMap; if (!g_cmd_list_file.empty()) { shared_ptr pbuff = get_file_buffer(g_cmd_list_file); if (pbuff == nullptr) return -1; if(parser_cmd_list_file(pbuff, &cmdmap)) return -1; pCmdMap = &cmdmap; } else { pCmdMap = &g_cmd_map; } if (pCmdMap->find(procotal) == pCmdMap->end()) { return 0; } return (*pCmdMap)[procotal]->run_all(p); } static int insert_one_cmd(const char * cmd, CmdMap *pCmdMap) { string s = cmd; size_t pos = 0; string pro = get_next_param(s, pos, ':'); pro = remove_square_brackets(pro); pro += ":"; pro = str_to_upper(pro); shared_ptr p = create_cmd_obj(s); if (p == nullptr) return -1; if (p->parser()) return -1; if (pCmdMap->find(pro) == pCmdMap->end()) { shared_ptr list(new CmdList); (*pCmdMap)[pro] = list; } (*pCmdMap)[pro]->push_back(p); return 0; } static int added_default_boot_cmd(const char *filename) { string str; str = "SDPS: boot -f "; str += "\""; str += filename; str += "\""; int ret = insert_one_cmd(str.c_str(), &g_cmd_map); if (ret) return ret; insert_one_cmd("SDPS: done", &g_cmd_map); str = "SDP: boot -f "; str += "\""; str += filename; str += "\""; ret = insert_one_cmd(str.c_str(), &g_cmd_map); if (ret) return ret; insert_one_cmd("SDP: done", &g_cmd_map); str = "SDPU: write -f "; str += "\""; str += filename; str += "\""; str += " -offset 0x57c00"; insert_one_cmd(str.c_str(), &g_cmd_map); insert_one_cmd("SDPU: jump", &g_cmd_map); insert_one_cmd("SDPU: done", &g_cmd_map); str = "SDPV: write -f "; str += "\""; str += filename; str += "\""; str += " -skipspl"; insert_one_cmd(str.c_str(), &g_cmd_map); insert_one_cmd("SDPV: jump", &g_cmd_map); insert_one_cmd("SDPV: done", &g_cmd_map); return 0; } int check_version(string str) { int x = 0; int ver = 0; for (size_t i = 0; i < str.size(); i++) { char c = str[i]; if (c >= '0' && c <= '9') { x *= 10; x += c - '0'; } if (c == '.' || i == str.size()-1 || c == '\n') { ver <<= 12; ver += x; x = 0; } } int cur = uuu_get_version(); if (ver > cur) { string str; str = "This version of uuu is too old, please download the latest one"; set_last_err_string(str); return -1; } return 0; } int uuu_run_cmd_script(const char * buff, int dry) { shared_ptr p(new FileBuffer((void*)buff, strlen(buff))); return parser_cmd_list_file(p); } int parser_cmd_list_file(shared_ptr pbuff, CmdMap *pCmdMap) { char uuu_version[] = "uuu_version"; string str; if (pCmdMap == nullptr) pCmdMap = &g_cmd_map; pCmdMap->clear(); for (size_t i = 0; i < pbuff->size(); i++) { uint8_t c = pbuff->at(i); if (c == '\r') continue; if(c != '\n') str.push_back(c); if (c == '\n' || c == 0 || i == pbuff->size() - 1) { if (str.substr(0, strlen(uuu_version)) == uuu_version) { if (check_version(str.substr(strlen(uuu_version), 10))) { return -1; } }else if (str.size() > 1) { if (str[0] != '#') if (insert_one_cmd(str.c_str(), pCmdMap)) return -1; } str.clear(); } } return 0; } int uuu_auto_detect_file(const char *filename) { string_ex fn; fn += remove_quota(filename); fn.replace('\\', '/'); if (fn.empty()) fn += "./"; string oldfn =fn; fn += "/uuu.auto"; shared_ptr buffer = get_file_buffer(fn); if (buffer == nullptr) { fn.clear(); fn += oldfn; size_t pos = str_to_upper(fn).find("ZIP"); if(pos == string::npos || pos != fn.size() - 3) { pos = str_to_upper(fn).find("SDCARD"); if (pos == string::npos || pos != fn.size() - 6) buffer = get_file_buffer(fn); //we don't try open a zip file here } if(buffer == nullptr) return -1; } string str= "uuu_version"; void *p1 = buffer->data(); void *p2 = (void*)str.data(); if (memcmp(p1, p2, str.size()) == 0) { size_t pos = fn.rfind('/'); if (pos != string::npos) set_current_dir(fn.substr(0, pos + 1)); g_cmd_list_file = fn.substr(pos+1); return parser_cmd_list_file(buffer); } //flash.bin or uboot.bin return added_default_boot_cmd(fn.c_str()); } int notify_done(uuu_notify nt, void *p) { if(nt.type == uuu_notify::NOTIFY_DONE) *(std::atomic *) p = 1; if (nt.type == uuu_notify::NOTIFY_CMD_END && nt.status) *(std::atomic *) p = 1; return 0; } int uuu_wait_uuu_finish(int deamon, int dry) { std::atomic exit; exit = 0; if(dry) { for(auto it=g_cmd_map.begin(); it != g_cmd_map.end(); it++) { for(auto cmd = it->second->begin(); cmd != it->second->end(); cmd++) { (*cmd)->dump(); } } return 0; } if (!deamon) uuu_register_notify_callback(notify_done, &exit); if(polling_usb(exit)) return -1; return 0; } mfgtools-uuu_1.4.193/libuuu/cmd.h000066400000000000000000000121271417203213400166420ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include #include #include #include class ConfigItem; std::string get_next_param(const std::string &cmd, size_t &pos, char sperate = ' '); class CmdCtx { public: CmdCtx() = default; CmdCtx(const CmdCtx&) = delete; CmdCtx& operator=(const CmdCtx&) = delete; virtual ~CmdCtx(); ConfigItem *m_config_item = nullptr; void *m_dev = nullptr; short m_current_bcd; }; class CmdUsbCtx : public CmdCtx { public: ~CmdUsbCtx() override; int look_for_match_device(const char * procotol); }; struct Param { enum class Type { e_uint32, e_uint64, e_bool, e_string, e_null, e_string_filename, }; const char * const key; const char * const Error; void *pData; const Type type; const bool ignore_case; Param(const char *ky, void *pD, Type tp, bool ignore = true, const char *error = nullptr) : key{ky}, Error{error}, pData{pD}, type{tp}, ignore_case{ignore} { } }; class CmdBase { public: CmdBase() = default; CmdBase(char *p) { if (p) m_cmd = p; } virtual ~CmdBase(); virtual int dump(); const std::string& get_cmd() const noexcept { return m_cmd; } bool get_lastcmd() const noexcept { return m_lastcmd; } void insert_param_info(const char *key, void *pD, Param::Type tp, bool ignore_case = true, const char* err = nullptr) { m_param.emplace_back(Param{key, pD, tp, ignore_case, err}); } virtual int parser_protocal(char *p, size_t &pos); virtual int parser(char *p = nullptr); virtual int run(CmdCtx *p) = 0; protected: bool m_bCheckTotalParam = false; std::string m_cmd; bool m_lastcmd = false; bool m_NoKeyParam = false; uint64_t m_timeout = 2000; private: std::vector m_param; }; using CreateCmdObj = std::shared_ptr (*) (char *); class CmdObjCreateMap:public std::map { public: CmdObjCreateMap(); }; class CmdDone :public CmdBase { public: CmdDone(char *p) :CmdBase(p) { m_lastcmd = true; } int run(CmdCtx *p) override; }; class CmdDelay :public CmdBase { public: CmdDelay(char *p) :CmdBase(p) {} int parser(char *p = nullptr) override; int run(CmdCtx *p) override; private: int m_ms = 0; }; class CmdError : public CmdBase { public: CmdError(char *p) :CmdBase(p) {} int parser(char *p = nullptr) override; int run(CmdCtx *p) override; private: std::string m_error; }; class CmdShell : public CmdBase { public: CmdShell(char *p) : CmdBase(p) {} int parser(char *p = nullptr) override; int run(CmdCtx *p) override; private: bool m_dyn = false; std::string m_protocal; std::string m_shellcmd; }; class CmdIf : public CmdBase { public: CmdIf(char *p) : CmdBase(p) {} int parser(char *p = nullptr) override; int run(CmdCtx *p) override; private: std::string m_condtion; std::string m_protocal; std::string m_true_cmd; void build_map(CmdCtx *p); }; class CmdEnv : public CmdBase { public: using CmdBase::CmdBase; int parser(char *p = nullptr) override; int run(CmdCtx *p) override; private: std::string m_unfold_cmd; }; class CmdList : public std::vector> { public: int run_all(CmdCtx *p, bool dry_run = false); }; class CmdMap : public std::map> { public: int run_all(const std::string &protocal, CmdCtx *p, bool dry_run = false); }; class CfgCmd :public CmdBase { public: CfgCmd(char *cmd) :CmdBase(cmd) {} int parser(char * /*p*/) override { return 0; } int run(CmdCtx *p) override; }; int run_cmds(const char *procotal, CmdCtx *p); int run_cmd(CmdCtx *pCtx, const char * cmd, int dry); int insert_env_variable(std::string key, std::string value); std::string get_env_variable(std::string key); int clear_env(); bool is_evn_exist(std::string key);mfgtools-uuu_1.4.193/libuuu/config.cpp000066400000000000000000000154261417203213400177040ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "config.h" #include "cmd.h" #include "libcomm.h" #include "liberror.h" #include "libuuu.h" using namespace std; static Config g_config; constexpr uint16_t FSL_VID = 0x15A2; constexpr uint16_t NXP_VID = 0x1FC9; constexpr uint16_t BD_VID = 0x3016; Config::Config() { emplace_back(ConfigItem{"SDPS:", "MX8QXP", nullptr, NXP_VID, 0x012F, 0x0002}); emplace_back(ConfigItem{"SDPS:", "MX8QM", "MX8QXP", NXP_VID, 0x0129, 0x0002}); emplace_back(ConfigItem{"SDPS:", "MX8DXL", "MX8QXP", NXP_VID, 0x0147}); emplace_back(ConfigItem{"SDPS:", "MX28", nullptr, FSL_VID, 0x004f}); emplace_back(ConfigItem{"SDPS:", "MX815", nullptr, NXP_VID, 0x013E}); emplace_back(ConfigItem{"SDPS:", "MX865", "MX815", NXP_VID, 0x0146}); emplace_back(ConfigItem{"SDPS:", "MX8ULP", "MX815", NXP_VID, 0x014A}); emplace_back(ConfigItem{"SDPS:", "MX8ULP", "MX815", NXP_VID, 0x014B}); emplace_back(ConfigItem{"SDP:", "MX7D", nullptr, FSL_VID, 0x0076}); emplace_back(ConfigItem{"SDP:", "MX6Q", nullptr, FSL_VID, 0x0054}); emplace_back(ConfigItem{"SDP:", "MX6D", "MX6Q", FSL_VID, 0x0061}); emplace_back(ConfigItem{"SDP:", "MX6SL", "MX6Q", FSL_VID, 0x0063}); emplace_back(ConfigItem{"SDP:", "MX6SX", "MX6Q", FSL_VID, 0x0071}); emplace_back(ConfigItem{"SDP:", "MX6UL", "MX7D", FSL_VID, 0x007D}); emplace_back(ConfigItem{"SDP:", "MX6ULL", "MX7D", FSL_VID, 0x0080}); emplace_back(ConfigItem{"SDP:", "MX6SLL", "MX7D", NXP_VID, 0x0128}); emplace_back(ConfigItem{"SDP:", "MX7ULP", nullptr, NXP_VID, 0x0126}); emplace_back(ConfigItem{"SDP:", "MXRT106X", nullptr, NXP_VID, 0x0135}); emplace_back(ConfigItem{"SDP:", "MX8MM", "MX8MQ", NXP_VID, 0x0134}); emplace_back(ConfigItem{"SDP:", "MX8MQ", "MX8MQ", NXP_VID, 0x012B}); emplace_back(ConfigItem{"SDPU:", "SPL", "SPL", 0x0525, 0xB4A4, 0, 0x04FF}); emplace_back(ConfigItem{"SDPV:", "SPL1", "SPL", 0x0525, 0xB4A4, 0x0500, 0x9998}); emplace_back(ConfigItem{"SDPV:", "SPL1", "SPL", NXP_VID, 0x0151, 0x0500, 0x9998}); emplace_back(ConfigItem{"SDPU:", "SPL", "SPL", 0x0525, 0xB4A4, 0x9999, 0x9999}); /*old i.MX8 MQEVk use bcd 9999*/ emplace_back(ConfigItem{"SDPU:", "SPL", "SPL", BD_VID, 0x1001, 0, 0x04FF}); emplace_back(ConfigItem{"SDPV:", "SPL1", "SPL", BD_VID, 0x1001, 0x0500, 0x9998}); emplace_back(ConfigItem{"FBK:", nullptr, nullptr, 0x066F, 0x9AFE}); emplace_back(ConfigItem{"FBK:", nullptr, nullptr, 0x066F, 0x9BFF}); emplace_back(ConfigItem{"FBK:", nullptr, nullptr, NXP_VID, 0x0153}); emplace_back(ConfigItem{"FB:", nullptr, nullptr, 0x0525, 0xA4A5}); emplace_back(ConfigItem{"FB:", nullptr, nullptr, 0x18D1, 0x0D02}); emplace_back(ConfigItem{"FB:", nullptr, nullptr, BD_VID, 0x0001}); emplace_back(ConfigItem{"FB:", nullptr, nullptr, NXP_VID, 0x0152}); } int uuu_for_each_cfg(uuu_show_cfg fn, void *p) { for (const auto &configItem : g_config) { if (fn(configItem.m_protocol.c_str(), configItem.m_chip.c_str(), configItem.m_compatible.c_str(), configItem.m_vid, configItem.m_pid, configItem.m_bcdVerMin, configItem.m_bcdVerMax, p)) return -1; } return 0; } Config * get_config() noexcept { return &g_config; } ConfigItem * Config::find(uint16_t vid, uint16_t pid, uint16_t ver) { for (auto it = begin(); it != end(); it++) { if (vid == it->m_vid && pid == it->m_pid) { if (ver >= it->m_bcdVerMin && ver <= it->m_bcdVerMax) return &(*it); } } return nullptr; } Config Config::find(const string &pro) { Config items; for (auto it = begin(); it != end(); it++) { if (it->m_protocol == pro) items.emplace_back(*it); } return items; } int CfgCmd::run(CmdCtx *) { size_t pos = 0; string param; ConfigItem item; param = get_next_param(m_cmd, pos); if (str_to_upper(param) == "CFG:") param = get_next_param(m_cmd, pos); if (param.empty()) { set_last_err_string("Wrong param"); return -1; } item.m_protocol = str_to_upper(param); bool conversion_succeeded = false; while (pos < m_cmd.size()) { param = get_next_param(m_cmd, pos); if (param == "-pid") { param = get_next_param(m_cmd, pos); item.m_pid = str_to_uint16(param, &conversion_succeeded); if (!conversion_succeeded) return -1; continue; } if (param == "-vid") { param = get_next_param(m_cmd, pos); item.m_vid = str_to_uint16(param, &conversion_succeeded); if (!conversion_succeeded) return -1; continue; } if (param == "-bcdversion") { param = get_next_param(m_cmd, pos); item.m_bcdVerMin = item.m_bcdVerMax = str_to_uint16(param, &conversion_succeeded); if (!conversion_succeeded) return -1; continue; } if (param == "-bcdmin") { param = get_next_param(m_cmd, pos); item.m_bcdVerMin = str_to_uint16(param, &conversion_succeeded); if (!conversion_succeeded) return -1; continue; } if (param == "-bcdmax") { param = get_next_param(m_cmd, pos); item.m_bcdVerMax = str_to_uint16(param, &conversion_succeeded); if (!conversion_succeeded) return -1; continue; } if (param == "-chip") { param = get_next_param(m_cmd, pos); item.m_chip = param; continue; } if (param == "-compatible") { param = get_next_param(m_cmd, pos); item.m_compatible = param; continue; } } ConfigItem *pItem= g_config.find(item.m_vid, item.m_pid, item.m_bcdVerMax); if (pItem) *pItem = item; else g_config.emplace_back(item); return 0; } mfgtools-uuu_1.4.193/libuuu/config.h000066400000000000000000000044241417203213400173450ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include #include #include class ConfigItem { public: ConfigItem() = default; ConfigItem(const char *pro, const char *chip, const char *comp, uint16_t vid, uint16_t pid, uint16_t verLow = 0, uint16_t verUp = UINT16_MAX) : m_pid{pid}, m_vid{vid}, m_bcdVerMin{verLow}, m_bcdVerMax{verUp} { if (pro) m_protocol = pro; if (chip) m_chip = chip; if (comp) m_compatible = comp; } std::string m_protocol; std::string m_chip; std::string m_compatible; uint16_t m_pid = 0; uint16_t m_vid = 0; uint16_t m_bcdVerMin = 0; uint16_t m_bcdVerMax = UINT16_MAX; }; class Config :public std::vector { public: Config(); ConfigItem *find(uint16_t vid, uint16_t pid, uint16_t ver); Config find(const std::string &protocal); }; Config * get_config() noexcept; mfgtools-uuu_1.4.193/libuuu/error.cpp000066400000000000000000000043251417203213400175640ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "liberror.h" #include "libuuu.h" #include "libusb.h" using namespace std; static string g_last_error_str; static int g_last_err_id; static uint32_t g_debug_level; int get_libusb_debug_level() noexcept { return g_debug_level & 0xFFFF; } void uuu_set_debug_level(uint32_t mask) { g_debug_level = mask; #if LIBUSB_API_VERSION > 0x01000106 libusb_set_option(nullptr, LIBUSB_OPTION_LOG_LEVEL, get_libusb_debug_level()); #else libusb_set_debug(nullptr, get_libusb_debug_level()); #endif } const char * uuu_get_last_err_string() { return g_last_error_str.c_str(); } void set_last_err_string(const string &str) { g_last_error_str = str; } int uuu_get_last_err() { return g_last_err_id; } void set_last_err_id(int id) { g_last_err_id = id; } mfgtools-uuu_1.4.193/libuuu/fastboot.cpp000066400000000000000000000514451417203213400202610ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ /* Android fastboot protocol define at https://android.googlesource.com/platform/system/core/+/master/fastboot/ */ #include #include "fastboot.h" #include "libcomm.h" #include "cmd.h" #include "buffer.h" #include "liberror.h" #include "libuuu.h" #include #include #include #include "sparse.h" #include "ffu_format.h" #include "libcomm.h" #include "trans.h" #include #include "rominfo.h" int FastBoot::Transport(string cmd, void *p, size_t size, vector *input) { if (m_pTrans->write((void*)cmd.data(), cmd.size())) return -1; char buff[65]; memset(buff, 0, 65); while ( strncmp(buff, "OKAY", 4) && strncmp(buff, "FAIL", 4)) { size_t actual; memset(buff, 0, 65); if (m_pTrans->read(buff, 64, &actual)) return -1; if (strncmp(buff, "DATA",4) == 0) { size_t sz; sz = strtoul(buff+4, nullptr, 16); if (input) { input->resize(sz); size_t rz; if (m_pTrans->read(input->data(), sz, &rz)) return -1; input->resize(rz); } else { if (sz > size) sz = size; if (m_pTrans->write(p, sz)) return -1; } }else { string s; s = buff + 4; m_info += s; uuu_notify nt; nt.type = uuu_notify::NOTIFY_CMD_INFO; nt.str = buff + 4; call_notify(nt); } } if (strncmp(buff, "OKAY", 4) == 0) return 0; set_last_err_string(m_info); return -1; } int FBGetVar::parser(char *p) { if (p) m_cmd = p; size_t pos = 0; string param = get_next_param(m_cmd, pos); if (param.find(':') != string::npos) param = get_next_param(m_cmd, pos); if (str_to_upper(param) != "GETVAR") { string err = "Unknown Command:"; err += param; set_last_err_string(err); return -1; } m_var = get_next_param(m_cmd, pos); return 0; } int FBGetVar::run(CmdCtx *ctx) { BulkTrans dev; if (dev.open(ctx->m_dev)) return -1; FastBoot fb(&dev); string cmd; cmd = "getvar:"; cmd += m_var; if (fb.Transport(cmd, nullptr, 0)) return -1; m_val = fb.m_info; string key = "@"; key += str_to_upper(m_var); key += "@"; insert_env_variable(key, str_to_upper(fb.m_info)); return 0; } int FBCmd::parser(char *p) { if (p) m_cmd = p; size_t pos = 0; string s; if (parser_protocal(p, pos)) return -1; s = get_next_param(m_cmd, pos); if (str_to_upper(s) != str_to_upper(m_fb_cmd)) { string err = "Unknown command: "; err += s; set_last_err_string(s); return -1; } if(pos!=string::npos && pos < m_cmd.size()) m_uboot_cmd = m_cmd.substr(pos); return 0; } int FBCmd::run(CmdCtx *ctx) { BulkTrans dev{m_timeout}; if (dev.open(ctx->m_dev)) return -1; FastBoot fb(&dev); string cmd; cmd = m_fb_cmd; cmd += m_separator; cmd += m_uboot_cmd; if (fb.Transport(cmd, nullptr, 0)) return -1; return 0; } int FBPartNumber::run(CmdCtx *ctx) { BulkTrans dev{m_timeout}; if (dev.open(ctx->m_dev)) return -1; FastBoot fb(&dev); string_ex cmd; cmd.format("%s:%s:%08x", m_fb_cmd.c_str(), m_partition_name.c_str(), (uint32_t)m_Size); if (fb.Transport(cmd, nullptr, 0)) return -1; return 0; } int FBUpdateSuper::run(CmdCtx *ctx) { BulkTrans dev{m_timeout}; if (dev.open(ctx->m_dev)) return -1; FastBoot fb(&dev); string_ex cmd; cmd.format("%s:%s:%s", m_fb_cmd.c_str(), m_partition_name.c_str(), m_opt.c_str()); if (fb.Transport(cmd, nullptr, 0)) return -1; return 0; } int FBDownload::run(CmdCtx *ctx) { BulkTrans dev; if (dev.open(ctx->m_dev)) return -1; FastBoot fb(&dev); shared_ptr buff = get_file_buffer(m_filename); if (buff == nullptr) return -1; string_ex cmd; cmd.format("download:%08x", buff->size()); if (fb.Transport(cmd, buff->data(), buff->size())) return -1; return 0; } int FBUpload::run(CmdCtx* ctx) { BulkTrans dev; if (dev.open(ctx->m_dev)) return -1; FastBoot fb(&dev); string_ex cmd; cmd.format("upload"); std::vector buff; if (fb.Transport(cmd, nullptr, buff.size(), &buff)) return -1; std::ofstream fout(m_filename, ios::out | ios::trunc); std::copy(buff.begin(), buff.end(), std::ostream_iterator(fout)); fout.flush(); fout.close(); return 0; } int FBCopy::parser(char *p) { if (p) m_cmd = p; size_t pos = 0; string s; s = get_next_param(m_cmd, pos); if (s.find(":") != s.npos) s = get_next_param(m_cmd, pos); if ((str_to_upper(s) != "UCP")) { string err = "Unknown command: "; err += s; set_last_err_string(s); return -1; } string source; string dest; source = get_next_param(m_cmd, pos); dest = get_next_param(m_cmd, pos); if (source.empty()) { set_last_err_string("ucp: source missed"); return -1; } if (dest.empty()) { set_last_err_string("ucp: destination missed"); return -1; } if (source.find("T:") == 0 || source.find("t:") == 0) { if (dest.find("T:") == 0 || dest.find("t:") == 0) { set_last_err_string("ucp just support one is remote file start with t:"); return -1; } m_target_file = source.substr(2); m_bDownload = false; //upload a file m_local_file = dest; } else if (dest.find("T:") == 0 || dest.find("t:") == 0) { m_target_file = dest.substr(2); m_bDownload = true; m_local_file = source; get_file_buffer(source, true); } else { set_last_err_string("ucp must a remote file name, start with t:"); return -1; } return 0; } int FBCopy::run(CmdCtx *ctx) { BulkTrans dev; if (dev.open(ctx->m_dev)) return -1; FastBoot fb(&dev); string_ex cmd; if(m_bDownload) { size_t i; shared_ptr buff = get_file_buffer(m_local_file); if (buff == nullptr) { return -1; } cmd.format("WOpen:%s", m_target_file.c_str()); if (fb.Transport(cmd, nullptr, 0)) { if (fb.m_info == "DIR") { Path p; p.append(m_local_file); string target = m_target_file; target += "/"; target += p.get_file_name(); cmd.format("WOpen:%s", target.c_str()); if (fb.Transport(cmd, nullptr, 0)) return -1; } else { return -1; } } uuu_notify nt; nt.type = uuu_notify::NOTIFY_TRANS_SIZE; nt.total = buff->size(); call_notify(nt); for (i = 0; i < buff->size(); i += this->m_Maxsize_pre_cmd) { size_t sz = buff->size() - i; if (sz > m_Maxsize_pre_cmd) sz = m_Maxsize_pre_cmd; cmd.format("donwload:%08X", sz); if (fb.Transport(cmd, buff->data() + i, sz)) { if (fb.m_info == "EPIPE") set_last_err_string("pipe closed by target"); else set_last_err_string("target return unknown error"); cmd.format("Close"); if (fb.Transport(cmd, nullptr, 0)) return -1; return -1; } nt.type = uuu_notify::NOTIFY_TRANS_POS; nt.index = i; call_notify(nt); } nt.type = uuu_notify::NOTIFY_TRANS_POS; nt.index = buff->size(); call_notify(nt); } else { cmd.format("ROpen:%s", m_target_file.c_str()); if (fb.Transport(cmd, nullptr, 0)) return -1; uuu_notify nt; nt.type = uuu_notify::NOTIFY_TRANS_SIZE; size_t total = nt.total = strtoul(fb.m_info.c_str(), nullptr, 16); call_notify(nt); nt.index = 0; ofstream of; struct stat st; Path localfile; localfile.append(m_local_file); if (stat(localfile.c_str(), &st) == 0) { if (st.st_mode & S_IFDIR) { localfile += "/"; Path t; t.append(m_target_file); localfile += t.get_file_name(); } } of.open(localfile, ofstream::binary); if (!of) { string err; err = "Fail to open file"; err += localfile; set_last_err_string(err); } do { vector data; if (fb.Transport("upload", nullptr, 0, &data)) return -1; of.write((const char*)data.data(), data.size()); nt.type = uuu_notify::NOTIFY_TRANS_POS; nt.index += data.size(); call_notify(nt); if (data.size() == 0) break; } while (nt.index < total || total == 0 ); // If total is 0, it is stream nt.type = uuu_notify::NOTIFY_TRANS_POS; call_notify(nt); } cmd.format("Close"); if (fb.Transport(cmd, nullptr, 0)) return -1; return 0; } int FBFlashCmd::parser(char *p) { if (FBCmd::parser(p)) return -1; string subcmd = m_uboot_cmd; size_t pos = 0; m_partition = get_next_param(subcmd, pos); if (m_partition == "-raw2sparse") { m_raw2sparse = true; m_partition = get_next_param(subcmd, pos); } if (m_partition == "-scanterm") { m_scanterm = true; m_partition = get_next_param(subcmd, pos); } if (m_partition == "-S") { m_partition = get_next_param(subcmd, pos); bool conversion_success = false; m_sparse_limit = str_to_uint64(m_partition, &conversion_success); if (!conversion_success) { set_last_err_string("FB: flash failed to parse size argument given to -S: "s + m_partition); return -1; } m_partition = get_next_param(subcmd, pos); } if (m_partition == "-scanlimited") { m_partition = get_next_param(subcmd, pos); bool conversion_success = false; m_scan_limited = str_to_uint64(m_partition, &conversion_success); if (!conversion_success) { set_last_err_string("FB: flash failed to parse size argument given to -scanlimited: "s + m_partition); return -1; } m_partition = get_next_param(subcmd, pos); } if (pos == string::npos || m_partition.empty()) { set_last_err_string("Missed partition name"); return -1; } m_filename = get_next_param(subcmd, pos); if (m_filename.empty()) { set_last_err_string("Missed file name"); return -1; } if (!check_file_exist(m_filename)) return -1; return 0; } int FBFlashCmd::flash(FastBoot *fb, void * pdata, size_t sz) { string_ex cmd; cmd.format("download:%08x", sz); if (fb->Transport(cmd, pdata, sz)) return -1; cmd.format("flash:%s", m_partition.c_str()); if (fb->Transport(cmd, nullptr, 0)) return -1; return 0; } int FBFlashCmd::flash_raw2sparse(FastBoot *fb, shared_ptr pdata, size_t block_size, size_t max) { SparseFile sf; vector data; if (max > m_sparse_limit) max = m_sparse_limit; sf.init_header(block_size, (max + block_size -1) / block_size); data.resize(block_size); uuu_notify nt; bool bload = pdata->IsKnownSize(); nt.type = uuu_notify::NOTIFY_TRANS_SIZE; if (bload) nt.total = pdata->size(); else nt.total = 0; call_notify(nt); size_t i = 0; int r; while (!(r=pdata->request_data(data, i*block_size, block_size))) { int ret = sf.push_one_block(data.data()); if (ret) { if (flash(fb, sf.m_data.data(), sf.m_data.size())) return -1; sf.init_header(block_size, (max + block_size - 1) / block_size); chunk_header_t ct; ct.chunk_type = CHUNK_TYPE_DONT_CARE; ct.chunk_sz = i + 1; ct.reserved1 = 0; ct.total_sz = sizeof(ct); sf.push_one_chuck(&ct, nullptr); nt.type = uuu_notify::NOTIFY_TRANS_POS; nt.total = i * block_size; call_notify(nt); } i++; if (bload != pdata->IsKnownSize()) { nt.type = uuu_notify::NOTIFY_TRANS_SIZE; nt.total = pdata->size(); call_notify(nt); bload = pdata->IsKnownSize(); } } if (r == ERR_OUT_MEMORY) return r; if (flash(fb, sf.m_data.data(), sf.m_data.size())) return -1; nt.type = uuu_notify::NOTIFY_TRANS_SIZE; nt.total = pdata->size(); call_notify(nt); nt.type = uuu_notify::NOTIFY_TRANS_POS; nt.total = pdata->size(); call_notify(nt); return 0; } int FBFlashCmd::run(CmdCtx *ctx) { FBGetVar getvar((char*)"FB: getvar max-download-size"); if (getvar.parser(nullptr)) return -1; if (getvar.run(ctx)) return -1; size_t max = getvar.m_val.empty() ? m_sparse_limit : str_to_uint32(getvar.m_val); BulkTrans dev{m_timeout}; if (dev.open(ctx->m_dev)) return -1; FastBoot fb(&dev); if (m_raw2sparse) { size_t block_size = 4096; if (getvar.parser((char*)"FB: getvar logical-block-size")) return -1; if (!getvar.run(ctx)) block_size = str_to_uint32(getvar.m_val); if (block_size == 0) { set_last_err_string("Device report block_size is 0"); return -1; } shared_ptr pdata = get_file_buffer(m_filename, true); if (isffu(pdata)) { string str; str = "FB: getvar partition-size:"; str += m_partition; if (getvar.parser((char*)str.c_str())) return -1; if (getvar.run(ctx)) return -1; m_totalsize = str_to_uint64(getvar.m_val); return flash_ffu(&fb, pdata); } return flash_raw2sparse(&fb, pdata, block_size, max); } shared_ptr pdata = get_file_buffer(m_filename, true); if (pdata == nullptr) return -1; pdata->request_data(sizeof(sparse_header)); if (SparseFile::is_validate_sparse_file(pdata->data(), sizeof(sparse_header))) { /* Limited max size to 16M for sparse file to avoid long timeout at read status*/ if (max > m_sparse_limit) max = m_sparse_limit; } if (m_scanterm) { pdata->request_data(m_scan_limited); size_t length,pos=0; if (IsMBR(pdata)) { length = ScanTerm(pdata, pos); if (length == 0) { set_last_err_string("This wic have NOT terminate tag after bootloader, please use new yocto"); return -1; } size_t offset = pos - length; if (offset < 0) { set_last_err_string("This wic boot length is wrong"); return -1; } return flash(&fb, pdata->data() + offset, length); } } if (pdata->size() <= max) { pdata->request_data(pdata->size()); if (flash(&fb, pdata->data(), pdata->size())) return -1; } else { size_t pos = 0; pdata->request_data(sizeof(sparse_header)); sparse_header * pfile = (sparse_header *)pdata->data(); if (!SparseFile::is_validate_sparse_file(pdata->data(), sizeof(sparse_header))) { set_last_err_string("Sparse file magic miss matched"); return -1; } SparseFile sf; size_t startblock; chunk_header_t * pheader; uuu_notify nt; nt.type = uuu_notify::NOTIFY_TRANS_SIZE; nt.total = pfile->total_blks; call_notify(nt); sf.init_header(pfile->blk_sz, max / pfile->blk_sz); startblock = 0; for(size_t nblk=0; nblk < pfile->total_chunks && pos <= pdata->size(); nblk++) { pdata->request_data(pos+sizeof(chunk_header_t)+sizeof(sparse_header)); size_t oldpos = pos; pheader = SparseFile::get_next_chunk(pdata->data(), pos); pdata->request_data(pos); size_t sz = sf.push_one_chuck(pheader, pheader + 1); if (sz == pheader->total_sz - sizeof(chunk_header_t)) { startblock += pheader->chunk_sz; } else if (sz == 0) { //whole chuck have not push into data. if (flash(&fb, sf.m_data.data(), sf.m_data.size())) return -1; sf.init_header(pfile->blk_sz, max / pfile->blk_sz); chunk_header_t ct; ct.chunk_type = CHUNK_TYPE_DONT_CARE; ct.chunk_sz = startblock; ct.reserved1 = 0; ct.total_sz = sizeof(ct); sz = sf.push_one_chuck(&ct, nullptr); /* roll back pos to previous failure chunck and let it push again into new sparse file. can't push it here because next chuck may big size chuck and need split as below else logic. */ pos = oldpos; nblk--; uuu_notify nt; nt.type = uuu_notify::NOTIFY_TRANS_POS; nt.total = startblock; call_notify(nt); } else { size_t off = ((uint8_t*)pheader) - pdata->data() + sz + sizeof(chunk_header_t); startblock += sz / pfile->blk_sz; do { if (flash(&fb, sf.m_data.data(), sf.m_data.size())) return -1; sf.init_header(pfile->blk_sz, max / pfile->blk_sz); chunk_header_t ct; ct.chunk_type = CHUNK_TYPE_DONT_CARE; ct.chunk_sz = startblock; ct.reserved1 = 0; ct.total_sz = sizeof(ct); sz = sf.push_one_chuck(&ct, nullptr); sz = sf.push_raw_data(pdata->data() + off, pos - off); off += sz; startblock += sz / pfile->blk_sz; uuu_notify nt; nt.type = uuu_notify::NOTIFY_TRANS_POS; nt.total = startblock; call_notify(nt); } while (off < pos); } } //send last data if (flash(&fb, sf.m_data.data(), sf.m_data.size())) return -1; sparse_header * pf = (sparse_header *)sf.m_data.data(); nt.type = uuu_notify::NOTIFY_TRANS_POS; nt.total = startblock + pf->total_blks; call_notify(nt); } return 0; } bool FBFlashCmd::isffu(shared_ptr p) { vector data; data.resize(sizeof(FFU_SECURITY_HEADER)); p->request_data(data, 0, sizeof(FFU_SECURITY_HEADER)); FFU_SECURITY_HEADER *h = (FFU_SECURITY_HEADER*)data.data(); if (strncmp((const char*)h->signature, FFU_SECURITY_SIGNATURE, sizeof(h->signature)) == 0) return true; else return false; } int FBFlashCmd::flash_ffu_oneblk(FastBoot *fb, shared_ptr p, size_t off, size_t blksz, size_t blkindex) { SparseFile sf; sf.init_header(blksz, 10); p->request_data(off + blksz); chunk_header_t ct; ct.chunk_type = CHUNK_TYPE_DONT_CARE; ct.chunk_sz = blkindex; ct.reserved1 = 0; ct.total_sz = sizeof(ct); sf.push_one_chuck(&ct, nullptr); if (sf.push_one_block(p->data() + off)) return -1; return flash(fb, sf.m_data.data(), sf.m_data.size()); } int FBFlashCmd::flash_ffu(FastBoot *fb, shared_ptr p) { p->request_data(sizeof(FFU_SECURITY_HEADER)); FFU_SECURITY_HEADER *h = (FFU_SECURITY_HEADER*)p->data(); if (strncmp((const char*)h->signature, FFU_SECURITY_SIGNATURE, sizeof(h->signature)) != 0) { set_last_err_string("Invalidate FFU Security header signature"); return -1; } size_t off; off = h->dwCatalogSize + h->dwHashTableSize; off = round_up(off, (size_t)h->dwChunkSizeInKb * 1024); p->request_data(off + sizeof(FFU_IMAGE_HEADER)); FFU_IMAGE_HEADER *pIh = (FFU_IMAGE_HEADER *)(p->data() + off); if (strncmp((const char*)pIh->Signature, FFU_SIGNATURE, sizeof(pIh->Signature)) != 0) { set_last_err_string("Invalidate FFU Security header signature"); return -1; } off += pIh->ManifestLength + pIh->cbSize; off = round_up(off, (size_t)h->dwChunkSizeInKb * 1024); p->request_data(off + sizeof(FFU_STORE_HEADER)); FFU_STORE_HEADER *pIs = (FFU_STORE_HEADER*) (p->data() + off); if(pIs->MajorVersion == 1) off += pIs->dwValidateDescriptorLength + offsetof(FFU_STORE_HEADER, NumOfStores); else off += pIs->dwValidateDescriptorLength + sizeof(FFU_STORE_HEADER); p->request_data(off + pIs->dwWriteDescriptorLength); size_t block_off = off + pIs->dwWriteDescriptorLength; block_off = round_up(block_off, (size_t)h->dwChunkSizeInKb * 1024); uuu_notify nt; nt.type = uuu_notify::NOTIFY_TRANS_SIZE; nt.total = pIs->dwWriteDescriptorCount; call_notify(nt); size_t currrent_block = 0; size_t i; for (i = 0; i < pIs->dwWriteDescriptorCount; i++) { FFU_BLOCK_DATA_ENTRY *entry = (FFU_BLOCK_DATA_ENTRY*)(p->data() + off); off += sizeof(FFU_BLOCK_DATA_ENTRY) + (entry->dwLocationCount -1) * sizeof(_DISK_LOCATION); if (currrent_block >= pIs->dwInitialTableIndex && currrent_block < pIs->dwInitialTableIndex + pIs->dwInitialTableCount) { //Skip Init Block } else { for (uint32_t loc = 0; loc < entry->dwLocationCount; loc++) { //printf("block 0x%x write to 0x%x seek %d\n", currrent_block, entry->rgDiskLocations[loc].dwBlockIndex, entry->rgDiskLocations[loc].dwDiskAccessMethod); uint32_t access = entry->rgDiskLocations[loc].dwDiskAccessMethod; uint32_t blockindex; if (entry->rgDiskLocations[loc].dwDiskAccessMethod == DISK_BEGIN) blockindex = entry->rgDiskLocations[loc].dwBlockIndex; else blockindex = m_totalsize / pIs->dwBlockSizeInBytes - 1 - entry->rgDiskLocations[loc].dwBlockIndex; for (uint32_t blk = 0; blk < entry->dwBlockCount; blk++) { if (flash_ffu_oneblk(fb, p, block_off + (currrent_block + blk) * pIs->dwBlockSizeInBytes, pIs->dwBlockSizeInBytes, blockindex + blk)) return -1; } } } nt.type = uuu_notify::NOTIFY_TRANS_POS; nt.total = i; call_notify(nt); currrent_block += entry->dwBlockCount; } nt.type = uuu_notify::NOTIFY_TRANS_POS; nt.total = i; call_notify(nt); return 0; } mfgtools-uuu_1.4.193/libuuu/fastboot.h000066400000000000000000000145221417203213400177210ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include "cmd.h" #include class FBFlashCmd; class FileBuffer; class TransBase; /* Android fastboot protocol define at https://android.googlesource.com/platform/system/core/+/master/fastboot/ */ class FastBoot { public: FastBoot(TransBase *p) : m_pTrans{p} {} int Transport(std::string cmd, void *p = nullptr, size_t size = 0, std::vector *input = nullptr); int Transport(std::string cmd, std::vector data, std::vector *input = nullptr) { return Transport(cmd, data.data(), data.size(), input); } std::string m_info; private: TransBase *const m_pTrans = nullptr; }; class FBGetVar : public CmdBase { public: FBGetVar(char *p) :CmdBase(p) {} int parser(char *p = nullptr) override; int run(CmdCtx *ctx) override; private: std::string m_val; std::string m_var; friend FBFlashCmd; }; class FBCmd: public CmdBase { public: FBCmd(char *p, std::string &&fb_cmd, char separator =':') : CmdBase(p), m_fb_cmd{std::move(fb_cmd)}, m_separator(separator) {} int parser(char *p = nullptr) override; int run(CmdCtx *ctx) override; protected: std::string m_uboot_cmd; private: const std::string m_fb_cmd; const char m_separator = ':'; }; class FBUCmd : public FBCmd { public: FBUCmd(char *p) :FBCmd(p, "UCmd") {} }; class FBACmd : public FBCmd { public: FBACmd(char *p) :FBCmd(p, "ACmd") {} }; class FBSyncCmd: public FBCmd { public: FBSyncCmd(char *p) : FBCmd(p, "Sync") {} }; class FBFlashingCmd : public FBCmd { public: FBFlashingCmd(char *p) : FBCmd(p, "flashing") {} }; class FBOemCmd : public FBCmd { public: FBOemCmd(char *p) : FBCmd(p, "oem", ' ') {} }; class FBFlashCmd : public FBCmd { public: FBFlashCmd(char *p) : FBCmd(p, "flash") { m_timeout = 10000; } int parser(char *p = nullptr) override; int run(CmdCtx *ctx) override; int flash(FastBoot *fb, void *p, size_t sz); int flash_raw2sparse(FastBoot *fb, std::shared_ptr p, size_t blksz, size_t max); bool isffu(std::shared_ptr p); int flash_ffu(FastBoot *fb, std::shared_ptr p); int flash_ffu_oneblk(FastBoot *fb, std::shared_ptr p, size_t off, size_t blksz, size_t blkindex); private: std::string m_filename; std::string m_partition; bool m_raw2sparse = false; size_t m_sparse_limit = 0x1000000; uint64_t m_totalsize; bool m_scanterm = false; uint64_t m_scan_limited = UINT64_MAX; }; class FBDelPartition : public FBCmd { public: FBDelPartition(char*p) : FBCmd(p, "delete-logical-partition") {} }; class FBPartNumber : public CmdBase { public: FBPartNumber(char *p, std::string &&fb_cmd) :CmdBase(p), m_fb_cmd{std::move(fb_cmd)} { m_Size = 0; m_bCheckTotalParam = true; m_NoKeyParam = true; insert_param_info(nullptr, &m_partition_name, Param::Type::e_string, false, "partition name"); insert_param_info(nullptr, &m_Size, Param::Type::e_uint32, false, "partition size"); } int run(CmdCtx *ctx) override; private: const std::string m_fb_cmd; std::string m_partition_name; uint32_t m_Size; }; class FBCreatePartition : public FBPartNumber { public: FBCreatePartition(char*p) :FBPartNumber(p, "create-logical-partition") {} }; class FBResizePartition : public FBPartNumber { public: FBResizePartition(char*p) :FBPartNumber(p, "resize-logical-partition") {} }; class FBUpdateSuper : public CmdBase { public: FBUpdateSuper(char *p) :CmdBase(p) { m_bCheckTotalParam = true; m_NoKeyParam = true; insert_param_info(nullptr, &m_partition_name, Param::Type::e_string, false, "partition name"); insert_param_info(nullptr, &m_opt, Param::Type::e_string, false, "partition size"); } int run(CmdCtx *ctx) override; private: const std::string m_fb_cmd = "update-super"; std::string m_opt; std::string m_partition_name; }; class FBEraseCmd : public FBCmd { public: FBEraseCmd(char *p) : FBCmd(p, "erase") {} }; class FBRebootCmd : public FBCmd { public: FBRebootCmd(char *p) : FBCmd(p, "reboot") {} }; class FBSetActiveCmd : public FBCmd { public: FBSetActiveCmd(char *p) : FBCmd(p, "set_active") {} }; class FBDownload : public CmdBase { public: FBDownload(char *p) :CmdBase(p) { insert_param_info("download", nullptr, Param::Type::e_null); insert_param_info("-f", &m_filename, Param::Type::e_string_filename); } int run(CmdCtx *ctx) override; private: std::string m_filename; }; class FBCopy : public CmdBase { public: FBCopy(char *p) :CmdBase(p) {} int parser(char *p = nullptr) override; int run(CmdCtx *ctx) override; private: bool m_bDownload; std::string m_local_file; size_t m_Maxsize_pre_cmd = 0x10000; std::string m_target_file; }; class FBContinueCmd : public FBCmd { public: FBContinueCmd(char *p) : FBCmd(p, "continue") {} }; class FBUpload : public CmdBase { public: FBUpload(char* p) : CmdBase(p) { insert_param_info("upload", nullptr, Param::Type::e_null); insert_param_info("-f", &m_filename, Param::Type::e_string); } int run(CmdCtx* ctx) override; private: std::string m_filename; }; mfgtools-uuu_1.4.193/libuuu/fat.cpp000066400000000000000000000117661417203213400172140ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include "libcomm.h" #include "libuuu.h" #include "liberror.h" #include "fat.h" int Fat::Open(string filename) { m_filename = filename; shared_ptr pbuff = get_file_buffer(m_filename); if (pbuff == nullptr) return -1; if (pbuff->size() < 512) { set_last_err_string("File too small"); return -1; } if (pbuff->at(510) != 0x55|| pbuff->at(511) != 0xAA) { set_last_err_string("Partition signature miss matched"); return -1; } Partition *pPart = (Partition *)(pbuff->data() + 446); m_fat_part_start = pPart->lba_start * 512; uint8_t *boot = pbuff->data() + m_fat_part_start; if (boot[510] != 0x55 || boot[511] != 0xAA) { set_last_err_string("Boot Sector signature miss matched"); return -1; } m_logical_sector_perfat = boot[0x16]; m_logical_sector_perfat += boot[0x17] << 8; if (m_logical_sector_perfat == 0) { m_logical_sector_perfat = boot[0x24]; m_logical_sector_perfat += boot[0x25] << 8; m_logical_sector_perfat += boot[0x26] << 16; m_logical_sector_perfat += boot[0x27] << 24; } m_fat_table_offset = boot[0xE]; m_fat_table_offset += boot[0xF] << 8; m_fat_table_offset *= 512; m_cluster = boot[0xD]; m_cluster *= 512; int num_of_fat = boot[0x10]; m_root_dir_offset = m_logical_sector_perfat * 512 * num_of_fat + m_fat_table_offset; m_num_of_rootdir = boot[0x11]; m_num_of_rootdir = boot[0x12] << 8; FatDirEntry *entry; entry = (FatDirEntry*)(boot + m_root_dir_offset); m_filemap.clear(); for (int i = 0; i < m_num_of_rootdir; i++) { string filename; if (entry->attr == 0x8) entry++; if (entry->filename[0] == 0) break; filename.clear(); while (entry->attr == 0xF) { filename.insert(0, lfn2string((FatLFN *)entry)); entry++; } if (filename.empty()) { filename.append((char*)entry->filename, 8); if (entry->ext[0]) { filename.append("."); filename.append((char*)entry->ext, 3); } } m_filemap[filename] = *entry; entry++; if (entry->filename[0] == 0) break; } return 0; } int Fat::get_next_cluster(shared_ptr p, int cluster) { uint16_t *pfat = (uint16_t*)(p->data() + m_fat_part_start + m_fat_table_offset); return pfat[cluster]; } void *Fat::get_data_buff(shared_ptr p, int cluster) { void *p1 = p->data() + m_fat_part_start + m_root_dir_offset + (cluster-2) * m_cluster + m_num_of_rootdir * 32; return p1; } int Fat::get_file_buff(string filename, shared_ptrp) { if (m_filemap.find(filename) == m_filemap.end()) { string err; err = "Can't find file "; err += filename; set_last_err_string(err); return -1; } shared_ptr pbuff = get_file_buffer(m_filename); size_t filesize = m_filemap[filename].file_size; p->resize(filesize); int cur = m_filemap[filename].start_cluster; size_t off; for (off = 0; off < filesize; off += m_cluster) { size_t sz; sz = filesize - off; if (sz > m_cluster) sz = m_cluster; if (cur == 0xFFFF) { set_last_err_string("Early finished at fat"); return -1; } void *pcluster = get_data_buff(pbuff, cur); memcpy(p->data() + off, pcluster, sz); cur = get_next_cluster(pbuff, cur); } return 0; } std::string Fat::lfn2string(FatLFN *p) { string str; for (int i = 0; i < 10; i += 2) if (p->name1[i] == 0) return str; else str += p->name1[i]; for (int i = 0; i < 12; i += 2) if (p->name2[i] == 0) return str; else str += p->name2[i]; for (int i = 0; i < 4; i += 2) if (p->name3[i] == 0) return str; else str += p->name3[i]; return str; } mfgtools-uuu_1.4.193/libuuu/fat.h000066400000000000000000000053431417203213400166530ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include "backfile.h" #include "buffer.h" #include #pragma pack(1) struct Partition { uint8_t status; uint8_t start_head; uint8_t start_sector; uint8_t start_cylinder; uint8_t type; uint8_t end_head; uint8_t end_sector; uint8_t end_cylinder; uint32_t lba_start; uint32_t lba_num; }; struct FatDirEntry { uint8_t filename[8]; uint8_t ext[3]; uint8_t attr; uint8_t user_attr; uint8_t delele_char; uint16_t create_time; uint16_t create_date; uint16_t userid; uint16_t access; uint16_t modify_time; uint16_t modify_date; uint16_t start_cluster; uint32_t file_size; }; struct FatLFN { uint8_t seq; uint8_t name1[10]; uint8_t attr; uint8_t type; uint8_t sum; uint8_t name2[12]; uint16_t start_cluster; uint8_t name3[4]; }; #pragma pack() class Fat : public Backfile { public: void *get_data_buff(shared_ptr p, int cluster); int get_file_buff(string filename, shared_ptrp); int get_next_cluster(shared_ptr p, int cluster); string lfn2string(FatLFN *p); int Open(string filename); map m_filemap; private: uint64_t m_cluster; uint64_t m_fat_part_start; uint64_t m_fat_table_offset; uint64_t m_logical_sector_perfat; int m_num_of_rootdir; uint64_t m_root_dir_offset; }; mfgtools-uuu_1.4.193/libuuu/ffu_format.h000066400000000000000000000113241417203213400202250ustar00rootroot00000000000000/* * Copyright 2020 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ //ref: https://docs.microsoft.com/en-us/windows-hardware/manufacture/mobile/ffu-image-format #ifndef LIBSPARSE_FFU_FORMAT_H #define LIBSPARSE_FFU_FORMAT_H #include #define FFU_SECURITY_SIGNATURE "SignedImage " #pragma pack(1) typedef struct _FFU_SECURITY_HEADER { uint32_t cbSize; // size of struct, overall uint8_t signature[12]; // "SignedImage " uint32_t dwChunkSizeInKb; // size of a hashed chunk within the image uint32_t dwAlgId; // algorithm used to hash uint32_t dwCatalogSize; // size of catalog to validate uint32_t dwHashTableSize; // size of hash table } FFU_SECURITY_HEADER; #define FFU_SIGNATURE "ImageFlash " typedef struct _IMAGE_HEADER { uint32_t cbSize; // sizeof(ImageHeader) uint8_t Signature[12]; // "ImageFlash " uint32_t ManifestLength; // in bytes uint32_t dwChunkSize; // Used only during image generation. } FFU_IMAGE_HEADER; typedef struct _STORE_HEADER { uint32_t dwUpdateType; // indicates partial or full flash uint16_t MajorVersion, MinorVersion; // used to validate struct uint16_t FullFlashMajorVersion, FullFlashMinorVersion; // FFU version, i.e. the image format uint8_t szPlatformId[192]; // string which indicates what device this FFU is intended to be written to uint32_t dwBlockSizeInBytes; // size of an image block in bytes - the device's actual sector size may differ uint32_t dwWriteDescriptorCount; // number of write descriptors to iterate through uint32_t dwWriteDescriptorLength; // total size of all the write descriptors, in bytes (included so they can be read out up front and interpreted later) uint32_t dwValidateDescriptorCount; // number of validation descriptors to check uint32_t dwValidateDescriptorLength; // total size of all the validation descriptors, in bytes uint32_t dwInitialTableIndex; // block index in the payload of the initial (invalid) GPT uint32_t dwInitialTableCount; // count of blocks for the initial GPT, i.e. the GPT spans blockArray[idx..(idx + count -1)] uint32_t dwFlashOnlyTableIndex; // first block index in the payload of the flash-only GPT (included so safe flashing can be accomplished) uint32_t dwFlashOnlyTableCount; // count of blocks in the flash-only GPT uint32_t dwFinalTableIndex; // index in the table of the real GPT uint32_t dwFinalTableCount; // number of blocks in the real GPT uint16_t NumOfStores; // Total number of stores (V2 only) uint16_t StoreIndex; // Current store index, 1-based (V2 only) uint64_t StorePayloadSize; // Payload data only, excludes padding (V2 only) uint16_t DevicePathLength; // Length of the device path (V2 only) uint16_t DevicePath[1]; // Device path has no NUL at then end (V2 only) } FFU_STORE_HEADER; typedef struct _VALIDATION_ENTRY { uint32_t dwSectorIndex; uint32_t dwSectorOffset; uint32_t dwByteCount; uint8_t rgCompareData[1]; // size is dwByteCount } FFU_VALIDATION_ENTRY; enum DISK_ACCESS_METHOD { DISK_BEGIN = 0, DISK_END = 2 }; typedef struct _DISK_LOCATION { uint32_t dwDiskAccessMethod; uint32_t dwBlockIndex; } FFU_DISK_LOCATION; typedef struct _BLOCK_DATA_ENTRY { uint32_t dwLocationCount; uint32_t dwBlockCount; FFU_DISK_LOCATION rgDiskLocations[1]; } FFU_BLOCK_DATA_ENTRY; #pragma pack() #endif // LIBSPARSE_FFU_FORMAT_H mfgtools-uuu_1.4.193/libuuu/gen_ver.sh000077500000000000000000000011051417203213400177040ustar00rootroot00000000000000#!/bin/sh # Input parameters file_to_write="$1" set -e if [ -f ../.tarball-version ] then echo "#define GIT_VERSION \"lib$(cat ../.tarball-version)\"" > "$file_to_write" exit 0 fi if [ "${APPVEYOR_BUILD_VERSION}" = "" ]; then echo build not in appveyor else git tag uuu_${APPVEYOR_BUILD_VERSION} fi # Test if we are in a repo if [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then #echo "In a repo" # Get the version of the last commit of the repo version=`git describe --tags --long` echo "#define GIT_VERSION \"lib$version\"" > $file_to_write fi mfgtools-uuu_1.4.193/libuuu/hidreport.cpp000066400000000000000000000055561417203213400204420ustar00rootroot00000000000000/* * Copyright 2020 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "hidreport.h" #include "libcomm.h" #include "liberror.h" #include "trans.h" #include HIDReport::~HIDReport() { } void HIDReport::notify(size_t index, uuu_notify::NOTIFY_TYPE type) { uuu_notify nf; nf.type = type; if(type == uuu_notify::NOTIFY_TRANS_POS) nf.index = index + m_postion_base; if (type == uuu_notify::NOTIFY_TRANS_SIZE) { nf.index = m_notify_total > index ? m_notify_total : index; } call_notify(nf); } int HIDReport::read(std::vector &buff) { if (buff.size() < m_size_in + m_size_payload) { set_last_err_string("buffer to small to get a package"); return -1; } size_t rs; int ret = m_pdev->read(buff.data(), m_size_in + m_size_payload, &rs); return ret; } int HIDReport::write(const void *p, size_t sz, uint8_t report_id) { notify(sz, uuu_notify::NOTIFY_TRANS_SIZE); const uint8_t * const buff = reinterpret_cast(p); size_t off = 0; for (; off < sz; off += m_size_out) { m_out_buff[0] = report_id; size_t s = sz - off; if (s > m_size_out) s = m_size_out; memcpy(m_out_buff.data() + m_size_payload, buff + off, s); int ret = m_pdev->write(m_out_buff.data(), report_id == 1? s + m_size_payload: m_size_out + m_size_payload); if (ret < 0) return -1; if (off % 0x1F == 0) { notify(off, uuu_notify::NOTIFY_TRANS_POS); } } notify(sz, uuu_notify::NOTIFY_TRANS_POS); return 0; } mfgtools-uuu_1.4.193/libuuu/hidreport.h000066400000000000000000000052021417203213400200730ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include "libuuu.h" #include class TransBase; class HIDReport { public: HIDReport(TransBase *trans) : m_pdev{trans} { m_out_buff.resize(m_size_out + m_size_payload); } virtual ~HIDReport(); size_t get_out_package_size() noexcept { return m_size_out; } virtual void notify(size_t index, uuu_notify::NOTIFY_TYPE type); int read(std::vector &buff); void set_notify_total(size_t notify_total) noexcept { m_notify_total = notify_total; } void set_out_package_size(size_t sz) { m_size_out = sz; m_out_buff.resize(m_size_out + m_size_payload); } void set_position_base(size_t position_base) noexcept { m_postion_base = position_base; } void set_skip_notify(bool skip_notify) noexcept { m_skip_notify = skip_notify; } int write(const void *p, size_t sz, uint8_t report_id); int write(const std::vector &buff, uint8_t report_id) { return write(buff.data(), buff.size(), report_id); } private: size_t m_notify_total = 0; std::vector m_out_buff; TransBase * const m_pdev = nullptr; size_t m_postion_base = 0; size_t m_size_in = 64; size_t m_size_out = 1024; size_t m_size_payload = 1; bool m_skip_notify = true; }; mfgtools-uuu_1.4.193/libuuu/http.cpp000066400000000000000000000226021417203213400174100ustar00rootroot00000000000000/* * Copyright 2019 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #ifdef _WIN32 // request += "Connection: Keep-Alive\n"; #include #include #include #pragma comment(lib, "Winhttp.lib") #else #include #include #include #define INVALID_SOCKET -1 #include #endif #include "http.h" #include "libuuu.h" #include "liberror.h" #include #include #include #ifdef UUUSSL #include #include class CUUUSSL { public: CUUUSSL() { #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_library_init(); SSLeay_add_ssl_algorithms(); SSL_load_error_strings(); #else OPENSSL_init_ssl(0, nullptr); SSLeay_add_ssl_algorithms(); #endif } ~CUUUSSL() { } }; static CUUUSSL g_uuussl; #endif using namespace std; #ifdef _WIN32 /* Win32 implement*/ HttpStream::HttpStream() { m_buff.empty(); m_hConnect = 0; m_hSession = 0; m_hRequest = 0; } int HttpStream::HttpGetHeader(std::string host, std::string path, int port, bool ishttps) { m_hSession = WinHttpOpen(L"WinHTTP UUU/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (!m_hSession) { set_last_err_string("fail WinHttpOpen"); return -1; } wstring_convert> converter; wstring whost = converter.from_bytes(host); if (m_hSession) m_hConnect = WinHttpConnect(m_hSession, whost.c_str(), port, 0); if (!m_hConnect) { set_last_err_string("Fail Connection"); return -1; } wstring wpath = converter.from_bytes(path); m_hRequest = WinHttpOpenRequest(m_hConnect, L"GET", wpath.c_str(), nullptr, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, ishttps ?WINHTTP_FLAG_SECURE:0); BOOL bResults = FALSE; if (!m_hRequest) { set_last_err_string("Fail WinHttpOpenRequest"); return -1; } bResults = WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); if (!bResults) { set_last_err_string("Fail WinHttpSendRequest"); return -1; } bResults = WinHttpReceiveResponse(m_hRequest, nullptr); if (!bResults) { set_last_err_string("Fail WinHttpReceiveResponse"); return -1; } DWORD status = 0; DWORD dwSize = sizeof(status); WinHttpQueryHeaders(m_hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status, &dwSize, WINHTTP_NO_HEADER_INDEX); if (status != HTTP_STATUS_OK) { set_last_err_string("HTTP status is not okay"); return -1; } return 0; } size_t HttpStream::HttpGetFileSize() { DWORD dwSize = 0; BOOL bResults = FALSE; wstring out; WinHttpQueryHeaders(m_hRequest, WINHTTP_QUERY_CONTENT_LENGTH, WINHTTP_HEADER_NAME_BY_INDEX, nullptr, &dwSize, WINHTTP_NO_HEADER_INDEX); // Allocate memory for the buffer. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { out.resize(dwSize / sizeof(WCHAR)); // Now, use WinHttpQueryHeaders to retrieve the header. bResults = WinHttpQueryHeaders(m_hRequest, WINHTTP_QUERY_CONTENT_LENGTH, WINHTTP_HEADER_NAME_BY_INDEX, (LPVOID)out.c_str(), &dwSize, WINHTTP_NO_HEADER_INDEX); } return _wtoll(out.c_str()); } int HttpStream::HttpDownload(char *buff, size_t sz) { DWORD dwSize = 0; DWORD dwDownloaded = 0; while (sz) { if (!WinHttpQueryDataAvailable(m_hRequest, &dwSize)) { set_last_err_string("WinHttpQueryDataAvailable"); return -1; } if (dwSize > sz) dwSize = sz; if (!WinHttpReadData(m_hRequest, (LPVOID)buff, dwSize, &dwDownloaded)) { set_last_err_string("Fail at WinHttpReadData"); return -1; } buff += dwDownloaded; sz -= dwDownloaded; } return 0; } HttpStream::~HttpStream() { if (m_hRequest) WinHttpCloseHandle(m_hRequest); if (m_hConnect) WinHttpCloseHandle(m_hConnect); if (m_hSession) WinHttpCloseHandle(m_hSession); } #else HttpStream::HttpStream() { m_buff.empty(); } int HttpStream::SendPacket(char *buff, size_t sz) { #ifdef UUUSSL if(m_ssl) return SSL_write((SSL*)m_ssl, buff, sz); #endif return send(m_socket, buff, sz, 0); } int HttpStream::RecvPacket(char *buff, size_t sz) { #ifdef UUUSSL if(m_ssl) return SSL_read((SSL*)m_ssl, buff, sz); #endif return recv(m_socket, buff, sz, 0); } int HttpStream::HttpGetHeader(std::string host, std::string path, int port, bool ishttps) { int ret; addrinfo *pAddrInfo; char s_port[10]; snprintf(s_port, 10, "%d", port); if (getaddrinfo(host.c_str(), s_port, 0, &pAddrInfo)) { set_last_err_string("get network address error"); return -1; } m_socket = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, pAddrInfo->ai_protocol); struct timeval tv; tv.tv_sec = 10; tv.tv_usec = 0; setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)); if (m_socket == INVALID_SOCKET) { set_last_err_string("Can't get sock"); return -1; } if (connect(m_socket, pAddrInfo->ai_addr, pAddrInfo->ai_addrlen)) { set_last_err_string("connect error"); return -1; } if(ishttps) { #ifdef UUUSSL const SSL_METHOD* meth = #if (OPENSSL_VERSION_NUMBER < 0x10100000L) TLSv1_2_client_method(); #else TLS_client_method(); #endif if(!meth) { set_last_err_string("Failure at TLSv1_2_client_method\n"); return -1; } SSL_CTX *ctx = SSL_CTX_new (meth); if(!ctx) { set_last_err_string("Error create ssl ctx\n"); return -1; } m_ssl = SSL_new (ctx); if(!m_ssl) { set_last_err_string("Error create SSL\n"); return -1; } SSL_set_fd((SSL*)m_ssl, m_socket); if( SSL_connect((SSL*)m_ssl) <= 0) { set_last_err_string("error build ssl connection"); return -1; } #else set_last_err_string("Can't support https"); return -1; #endif } if(ishttps) path = "https://" + host + path; string request = "GET " + path + " HTTP/1.1\r\n"; request += "Host: " + host + "\r\n\r\n"; ret = SendPacket((char*)request.c_str(), request.size()); if (ret != request.size()) { set_last_err_string("http send error"); return -1; } m_buff.resize(1024); ret = RecvPacket((char*)m_buff.data(), m_buff.size()); if (ret < 0) { set_last_err_string("http recv Error"); return -1; } int i; for (i = 0; i < 1024 - 4; i++) { if (m_buff[i] == 0xd && m_buff[i + 1] == 0xa && m_buff[i + 2] == 0xd && m_buff[i + 3] == 0xa) { break; } } if (i >= 1024 - 4) { set_last_err_string("Can't find termaniate"); return -1; } m_data_start = i + 4; string str; str.resize(i + 2); memcpy((void*)str.c_str(), m_buff.data(), i + 2); if (parser_response(str)) return -1; return 0; } size_t HttpStream::HttpGetFileSize() { return atoll(m_response["Content-Length"].c_str()); } int HttpStream::parser_response(string rep) { size_t pos = rep.find("\r\n"); if (pos == string::npos) { set_last_err_string("Can't find \r\n"); return -1; } string str = rep.substr(0, pos); if (str != "HTTP/1.1 200 OK") { set_last_err_string(str); return -1; } m_response.clear(); while (pos != string::npos) { pos += 2; size_t split = rep.find(':', pos); if (split == string::npos) break; string key = rep.substr(pos, split - pos); pos = rep.find("\r\n", pos); string value = rep.substr(split + 1, pos - split - 1); m_response[key] = value; } return 0; } int HttpStream::HttpDownload(char *buff, size_t sz) { size_t left = 0; if (m_data_start < m_buff.size()) left = m_buff.size() - m_data_start; size_t trim_transfered = 0; if (left) { trim_transfered = sz; if (trim_transfered > left) trim_transfered = left; memcpy(buff, m_buff.data() + m_data_start, trim_transfered); m_data_start += trim_transfered; } if (trim_transfered < sz) { int ret = 0; sz -= trim_transfered; buff += trim_transfered; while (sz && ((ret = RecvPacket(buff, sz)) > 0)) { buff += ret; sz -= ret; } if (ret < 0) { set_last_err_string("recv error"); return -1; } } return 0; } HttpStream::~HttpStream() { close(m_socket); #ifdef UUUSSL if(m_ssl) { SSL_CTX_free(SSL_get_SSL_CTX((SSL*)m_ssl)); SSL_free((SSL*)m_ssl); } #endif } #endif mfgtools-uuu_1.4.193/libuuu/http.h000066400000000000000000000042121417203213400170520ustar00rootroot00000000000000/* * Copyright 2020 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include #include #include class HttpStream { std::vector m_buff; int m_socket = -1; std::map m_response; size_t m_data_start; #ifdef _WIN32 void far * m_hSession; void far * m_hConnect; void far * m_hRequest; #endif void * m_ssl = nullptr; int parser_response(std::string rep); public: HttpStream(); int HttpGetHeader(std::string host, std::string path, int port = 80, bool ishttps=false); size_t HttpGetFileSize(); int HttpDownload(char *buff, size_t sz); ~HttpStream(); private: int RecvPacket(char *buff, size_t sz); int SendPacket(char *buff, size_t sz); }; mfgtools-uuu_1.4.193/libuuu/libcomm.h000066400000000000000000000101261417203213400175160ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #pragma once using namespace std; void call_notify(struct uuu_notify nf); #define log printf #define dbg printf int get_libusb_debug_level() noexcept; class string_ex : public std::string { public: int format(const char *fmt, ...) { va_list args; va_start(args, fmt); size_t len = std::vsnprintf(nullptr, 0, fmt, args); va_end(args); this->resize(len); va_start(args, fmt); std::vsnprintf((char*)c_str(), len+1, fmt, args); va_end(args); return 0; } void replace(char a, char b) { for (size_t i = 0; i < size(); i++) if (at(i) == a) (*this)[i] = b; } }; class Path : public string_ex { public: string get_file_name() { replace('\\', '/'); size_t pos; pos = rfind('/'); if (pos == string::npos) return *this; return substr(pos + 1); } }; inline uint64_t EndianSwap(uint64_t x) { return (((x & 0x00000000000000ffLL) << 56) | ((x & 0x000000000000ff00LL) << 40) | ((x & 0x0000000000ff0000LL) << 24) | ((x & 0x00000000ff000000LL) << 8) | ((x & 0x000000ff00000000LL) >> 8) | ((x & 0x0000ff0000000000LL) >> 24) | ((x & 0x00ff000000000000LL) >> 40) | ((x & 0xff00000000000000LL) >> 56)); } inline uint32_t EndianSwap(uint32_t x) { return (x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24); } inline uint16_t EndianSwap(uint16_t x) { return (x >> 8) | ((x << 8) & 0xFF00); } inline string str_to_upper(const string &str) { std::locale loc; string s; for (size_t i = 0; i < str.size(); i++) s.push_back(std::toupper(str[i], loc)); return s; } inline string remove_quota(string str) { if (!str.empty()) { if (str[0] == '"') { str.erase(0, 1); if (!str.empty() && str[str.size() - 1] == '"') str.erase(str.size() - 1, 1); } } return str; } inline bool compare_str(const string &str1, const string &str2, bool ignore_case) { if (ignore_case) return str_to_upper(str1) == str_to_upper(str2); else return str1 == str2; } uint16_t str_to_uint16(const string &str, bool * conversion_suceeded = nullptr); uint32_t str_to_uint32(const string &str, bool * conversion_suceeded = nullptr); uint64_t str_to_uint64(const string &str, bool * conversion_suceeded = nullptr); template inline T round_up(T x, T align) { return (x + align - 1) / align * align; } inline std::string trim(const std::string &s) { auto wsfront = std::find_if_not(s.begin(), s.end(), [](int c) {return std::isspace(c); }); return std::string(wsfront, std::find_if_not(s.rbegin(), std::string::const_reverse_iterator(wsfront), [](int c) {return std::isspace(c); }).base()); } mfgtools-uuu_1.4.193/libuuu/liberror.h000066400000000000000000000031461417203213400177200ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include void set_last_err_string(const std::string &str); void set_last_err_id(int id); #define ERR_OUT_MEMORY -2mfgtools-uuu_1.4.193/libuuu/libuuu.h000066400000000000000000000100331417203213400173760ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __libuuu___ #define __libuuu___ #include #include #ifdef __cplusplus #define EXT extern "C" #else #define EXT #endif /** * Get Last error string * @return last error string */ EXT const char * uuu_get_last_err_string(); /** * Get Last error code * @return last error code */ EXT int uuu_get_last_err(); EXT const char * uuu_get_version_string(); /** * 1.0.1 * bit[31:24].bit[23:12].bit[11:0] */ EXT int uuu_get_version(); struct uuu_notify { enum NOTIFY_TYPE { NOTIFY_CMD_TOTAL, NOTIFY_CMD_START, /* str is command name*/ NOTIFY_CMD_END, /* status show command finish status. 0 is success. Other failure.*/ NOTIFY_CMD_INDEX, /*Current running command index*/ NOTIFY_CMD_INFO, /* Status info string */ NOTIFY_PHASE_TOTAL, NOTIFY_PHASE_INDEX, /*Current running phase*/ NOTIFY_TRANS_SIZE, /*Total size*/ NOTIFY_TRANS_POS, /*Current finished transfer pos*/ NOTIFY_WAIT_FOR, NOFITY_DEV_ATTACH, NOTIFY_DECOMPRESS_START, NOTIFY_DECOMPRESS_SIZE, NOTIFY_DECOMPRESS_POS, NOTIFY_DOWNLOAD_START, NOTIFY_DOWNLOAD_END, NOTIFY_THREAD_EXIT, NOTIFY_DONE, }; NOTIFY_TYPE type; uint64_t id; uint64_t timestamp; union { int status; size_t index; size_t total; char *str; }; }; typedef int (*uuu_notify_fun)(struct uuu_notify, void *data); int uuu_register_notify_callback(uuu_notify_fun f, void *data); int uuu_unregister_notify_callback(uuu_notify_fun f); typedef int(*uuu_show_cfg)(const char *pro, const char *chip, const char *comp, uint16_t vid, uint16_t pid, uint16_t bcdlow, uint16_t bcdhigh, void *p); int uuu_for_each_cfg(uuu_show_cfg fn, void *p); typedef int(*uuu_ls_file)(const char *path, void *p); int uuu_for_each_ls_file(uuu_ls_file fn, const char *path, void *p); typedef int(*uuu_ls_usb_devices)(const char *path, const char *chip, const char *pro, uint16_t vid, uint16_t pid, uint16_t bcd, void *p); int uuu_for_each_devices(uuu_ls_usb_devices fn, void *p); int uuu_run_cmd(const char * cmd, int dry); int uuu_run_cmd_script(const char *script, int dry); int uuu_auto_detect_file(const char * filename); int uuu_wait_uuu_finish(int deamon, int dry); int uuu_add_usbpath_filter(const char *path); /*Set timeout wait for known devices appeared*/ int uuu_set_wait_timeout(int timeout_in_seconds); /*Set timeout wait for next devices appeared, e.g. FB -> FBK*/ int uuu_set_wait_next_timeout(int timeout_in_seconds); /*Set usb device polling period */ void uuu_set_poll_period(int period_in_milliseconds); /* * bit 0:15 for libusb * bit 16:31 for uuu */ void uuu_set_debug_level(uint32_t mask); #endif mfgtools-uuu_1.4.193/libuuu/notify.cpp000066400000000000000000000051041417203213400177370ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "libuuu.h" #include #include #include #include #include using namespace std; static map g_notification_map; static mutex g_mutex_notify; using namespace std::chrono; static const time_point g_now = steady_clock::now(); int uuu_register_notify_callback(uuu_notify_fun f, void *data) { std::lock_guard lock(g_mutex_notify); return g_notification_map.emplace(f, data).second ? 0 : 1; } int uuu_unregister_notify_callback(uuu_notify_fun f) { std::lock_guard lock(g_mutex_notify); return g_notification_map.erase(f) > 0 ? 0 : 1; } void call_notify(struct uuu_notify nf) { //Change RW lock later; std::lock_guard lock(g_mutex_notify); nf.id = std::hash{}(std::this_thread::get_id()); nf.timestamp = static_cast( duration_cast(steady_clock::now() - g_now).count()); for (const auto &item : g_notification_map) { try { item.first(nf, item.second); } catch (const std::exception& e) { std::cerr << "notify exception: " << e.what() << std::endl; } } } mfgtools-uuu_1.4.193/libuuu/rominfo.cpp000066400000000000000000000150501417203213400201010ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "rominfo.h" #include "buffer.h" #include "config.h" #include "libcomm.h" #include #include using namespace std; static constexpr std::array g_RomInfo { ROM_INFO{ "MX6Q", 0x00910000, ROM_INFO_HID | ROM_INFO_HID_MX6 }, ROM_INFO{ "MX6D", 0x00910000, ROM_INFO_HID | ROM_INFO_HID_MX6 }, ROM_INFO{ "MX6SL", 0x00910000, ROM_INFO_HID | ROM_INFO_HID_MX6 }, ROM_INFO{ "MX7D", 0x00911000, ROM_INFO_HID | ROM_INFO_HID_MX6 | ROM_INFO_HID_SKIP_DCD }, ROM_INFO{ "MX6UL", 0x00910000, ROM_INFO_HID | ROM_INFO_HID_MX6 | ROM_INFO_HID_SKIP_DCD }, ROM_INFO{ "MX6ULL", 0x00910000, ROM_INFO_HID | ROM_INFO_HID_MX6 | ROM_INFO_HID_SKIP_DCD }, ROM_INFO{ "MX6SLL", 0x00910000, ROM_INFO_HID | ROM_INFO_HID_MX6 | ROM_INFO_HID_SKIP_DCD }, ROM_INFO{ "MX8MQ", 0x00910000, ROM_INFO_HID | ROM_INFO_HID_MX6 | ROM_INFO_HID_SKIP_DCD }, ROM_INFO{ "MX7ULP", 0x2f018000, ROM_INFO_HID | ROM_INFO_HID_MX6 | ROM_INFO_HID_SKIP_DCD }, ROM_INFO{ "MXRT106X", 0x1000, ROM_INFO_HID | ROM_INFO_HID_MX6 | ROM_INFO_HID_SKIP_DCD }, ROM_INFO{ "MX8QXP", 0x0, ROM_INFO_HID | ROM_INFO_HID_NO_CMD | ROM_INFO_HID_UID_STRING }, ROM_INFO{ "MX28", 0x0, ROM_INFO_HID}, ROM_INFO{ "MX815", 0x0, ROM_INFO_HID | ROM_INFO_HID_NO_CMD | ROM_INFO_HID_UID_STRING | ROM_INFO_HID_EP1 | ROM_INFO_HID_PACK_SIZE_1020 | ROM_INFO_HID_ROMAPI}, ROM_INFO{ "SPL", 0x0, ROM_INFO_HID | ROM_INFO_HID_MX6 | ROM_INFO_SPL_JUMP | ROM_INFO_HID_SDP_NO_MAX_PER_TRANS}, ROM_INFO{ "SPL1", 0x0, ROM_INFO_HID | ROM_INFO_HID_MX6 | ROM_INFO_SPL_JUMP | ROM_INFO_HID_SDP_NO_MAX_PER_TRANS | ROM_INFO_AUTO_SCAN_UBOOT_POS}, }; const ROM_INFO * search_rom_info(const std::string &s) { for (const auto &rom_info : g_RomInfo) { if (s == rom_info.m_name) { return &rom_info; } } return nullptr; } const ROM_INFO * search_rom_info(const ConfigItem *item) { if (item == nullptr) { return nullptr; } const ROM_INFO * const p = search_rom_info(item->m_chip); if (p) { return p; } return search_rom_info(item->m_compatible); } #define IV_MAX_LEN 32 #define HASH_MAX_LEN 64 #define CONTAINER_HDR_ALIGNMENT 0x400 static constexpr uint8_t CONTAINER_TAG = 0x87; #pragma pack (1) struct rom_container { uint8_t version; uint8_t length_l; uint8_t length_m; uint8_t tag; uint32_t flags; uint16_t sw_version; uint8_t fuse_version; uint8_t num_images; uint16_t sig_blk_offset; uint16_t reserved; }; struct rom_bootimg { uint32_t offset; uint32_t size; uint64_t destination; uint64_t entry; uint32_t flags; uint32_t meta; uint8_t hash[HASH_MAX_LEN]; uint8_t iv[IV_MAX_LEN]; }; static constexpr uint32_t IMG_V2X = 0x0B; #pragma pack () size_t GetContainerActualSize(shared_ptr p, size_t offset, bool bROMAPI) { if(bROMAPI) return p->size() - offset; auto hdr = reinterpret_cast(p->data() + offset + CONTAINER_HDR_ALIGNMENT); if (hdr->tag != CONTAINER_TAG) { return p->size() - offset; } /* Check if include V2X container*/ auto image = reinterpret_cast(p->data() + offset + CONTAINER_HDR_ALIGNMENT + sizeof(struct rom_container)); unsigned int cindex = 1; if ((image->flags & 0xF) == IMG_V2X) { cindex = 2; hdr = reinterpret_cast(p->data() + offset + cindex * CONTAINER_HDR_ALIGNMENT); if (hdr->tag != CONTAINER_TAG) { return p->size() - offset; } } image = reinterpret_cast(p->data() + offset + cindex * CONTAINER_HDR_ALIGNMENT + sizeof(struct rom_container) + sizeof(struct rom_bootimg) * (hdr->num_images - 1)); uint32_t sz = image->size + image->offset + cindex * CONTAINER_HDR_ALIGNMENT; sz = round_up(sz, static_cast(CONTAINER_HDR_ALIGNMENT)); if (sz > (p->size() - offset)) { return p->size() - offset; } return sz; } bool CheckHeader(uint32_t *p) { static constexpr std::array FlashHeaderMagic { 0xc0ffee01, 0x42464346 }; for (const auto magic_val : FlashHeaderMagic) { if (*p == magic_val) { return true; } } return false; } size_t GetFlashHeaderSize(shared_ptr p, size_t offset) { static constexpr std::array offsets { 0, 0x400, 0x1fc, 0x5fc }; for (const auto test_offset : offsets) { if (p->m_avaible_size < (offset + test_offset)) { return 0; } if (CheckHeader(reinterpret_cast(p->data() + offset + test_offset))) { return 0x1000; } } return 0; } bool IsMBR(shared_ptr p) { uint16_t * m = (uint16_t *)(p->data() + 510); if (*m == 0xaa55) return true; return false; } size_t ScanTerm(std::shared_ptr p, size_t &pos, size_t offset, size_t limited) { const char *tag = "UUUBURNXXOEUZX7+A-XY5601QQWWZ"; if (limited >= p->m_avaible_size) limited = p->m_avaible_size; limited = limited - strlen(tag) - 64; if (offset > limited) return 0; for (size_t i = offset; i < limited; i++) { char *c = (char*)p->data() + i; size_t length = strlen(tag); size_t j; for (j = 0; j < length; j++) { if (tag[j] != c[j]) break; } if (j == length) { pos = i; return atoll(c + length); } } return 0; }mfgtools-uuu_1.4.193/libuuu/rominfo.h000066400000000000000000000055531417203213400175550ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include #include #include class ConfigItem; class FileBuffer; constexpr uint32_t ROM_INFO_HID = 0x1; constexpr uint32_t ROM_INFO_HID_MX23 = 0x2; constexpr uint32_t ROM_INFO_HID_MX50 = 0x4; constexpr uint32_t ROM_INFO_HID_MX6 = 0x8; constexpr uint32_t ROM_INFO_HID_SKIP_DCD = 0x10; constexpr uint32_t ROM_INFO_HID_MX8_MULTI_IMAGE = 0x20; constexpr uint32_t ROM_INFO_HID_MX8_STREAM = 0x40; constexpr uint32_t ROM_INFO_HID_UID_STRING = 0x80; // Omitted value: 0x100 // Omitted value: 0x200 constexpr uint32_t ROM_INFO_HID_NO_CMD = 0x400; constexpr uint32_t ROM_INFO_SPL_JUMP = 0x800; constexpr uint32_t ROM_INFO_HID_EP1 = 0x1000; constexpr uint32_t ROM_INFO_HID_PACK_SIZE_1020 = 0x2000; constexpr uint32_t ROM_INFO_HID_SDP_NO_MAX_PER_TRANS = 0x4000; constexpr uint32_t ROM_INFO_AUTO_SCAN_UBOOT_POS = 0x8000; constexpr uint32_t ROM_INFO_HID_ROMAPI = 0x10000; struct ROM_INFO { const char * m_name; uint32_t free_addr; uint32_t flags; }; const ROM_INFO * search_rom_info(const std::string &s); const ROM_INFO * search_rom_info(const ConfigItem *item); size_t GetContainerActualSize(std::shared_ptr p, size_t offset, bool bROMAPI=false); size_t GetFlashHeaderSize(std::shared_ptr p, size_t offset = 0); bool IsMBR(std::shared_ptr p); size_t ScanTerm(std::shared_ptr p, size_t &pos, size_t offset=512, size_t limited=0x800000); mfgtools-uuu_1.4.193/libuuu/sdp.cpp000066400000000000000000000424151417203213400172230ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include "sdps.h" #include "hidreport.h" #include "liberror.h" #include "libcomm.h" #include "buffer.h" #include "sdp.h" #include "rominfo.h" #include "libusb.h" #include "trans.h" #include int SDPCmdBase::check_ack(HIDReport *report, uint32_t ack) { if (get_hab_type(report) == HabUnknown) return -1; uint32_t status; if (get_status(report, status, 4)) return -1; if (ack != status) { set_last_err_string("Status Miss matched"); return -1; } return 0; } SDPCmdBase::HAB_t SDPCmdBase::get_hab_type(HIDReport *report) { uint32_t status; if (get_status(report, status, 3)) return HabUnknown; if (status == HabEnabled) return HabEnabled; if (status == HabDisabled) return HabDisabled; set_last_err_string("unknown hab type"); return HabUnknown; } int SDPCmdBase::get_status(HIDReport *p, uint32_t &status, uint8_t report_id) { m_input.resize(1025); m_input[0] = report_id; int ret = p->read(m_input); if (ret < 0) return -1; if (m_input.size() < (1 + sizeof(uint32_t))) { set_last_err_string("HID report size is too small"); return -1; } status = *(uint32_t*)(m_input.data() + 1); return 0; } int SDPCmdBase::init_cmd() { memset(&m_spdcmd, 0, sizeof(m_spdcmd)); insert_param_info("-scanlimited", &m_scan_limited, Param::Type::e_uint64); return 0; } IvtHeader *SDPCmdBase::search_ivt_header(shared_ptr data, size_t &off, size_t limit) { if (limit >= data->m_avaible_size) limit = data->m_avaible_size; for (; off < limit; off += 0x4) { IvtHeader *p = (IvtHeader*)(data->data() + off); if (p->IvtBarker == IVT_BARKER_HEADER) return p; if (p->IvtBarker == IVT_BARKER2_HEADER) { BootData *pDB = (BootData *) &(data->at(off + p->BootData - p->SelfAddr)); /*Skip HDMI firmware for i.MX8MQ*/ if (pDB->PluginFlag & 0xFFFFFFFE) continue; return p; } } off = -1; return nullptr; } int SDPCmdBase::send_cmd(HIDReport *p) { return p->write(&m_spdcmd, sizeof(m_spdcmd), 1); } SDPDcdCmd::SDPDcdCmd(char *p) : SDPCmdBase(p) { insert_param_info("dcd", nullptr, Param::Type::e_null); insert_param_info("-f", &m_filename, Param::Type::e_string_filename); insert_param_info("-dcdaddr", &m_dcd_addr, Param::Type::e_uint32); m_dcd_addr = 0; } int SDPDcdCmd::run(CmdCtx*ctx) { const ROM_INFO * rom = search_rom_info(ctx->m_config_item); if (rom == nullptr) { string_ex err; err.format("%s:%d can't get rom info", __FUNCTION__, __LINE__); set_last_err_string(err); return -1; } init_cmd(); shared_ptr buff, p = get_file_buffer(m_filename, true); if (!p) return -1; buff = p->request_data(0, m_scan_limited); size_t off = 0; IvtHeader *pIVT = search_ivt_header(buff, off); if (pIVT == nullptr) { return 0; } if (pIVT->DCDAddress == 0) return 0; uint8_t * pdcd = &(buff->at(off + pIVT->DCDAddress - pIVT->SelfAddr)); if (pdcd[0] != HAB_TAG_DCD) { string_ex err; err.format("%s:%d DCD TAG miss matched", __FUNCTION__, __LINE__); set_last_err_string(err); return -1; } uint32_t size = (pdcd[1] << 8) | pdcd[2]; if (size >= m_scan_limited) { set_last_err_string("dcd bigger than 8M"); return -1; } // point maybe change after new requestion buffer. pdcd = &(buff->at(off + pIVT->DCDAddress - pIVT->SelfAddr)); m_spdcmd.m_cmd = ROM_KERNEL_CMD_DCD_WRITE; m_spdcmd.m_addr = EndianSwap(m_dcd_addr ? m_dcd_addr : rom->free_addr); m_spdcmd.m_count = EndianSwap(size); HIDTrans dev; if (dev.open(ctx->m_dev)) return -1; HIDReport report(&dev); if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1)) return -1; if (report.write(pdcd, size, 2)) return -1; if (check_ack(&report, ROM_WRITE_ACK)) return -1; return 0; } SDPSkipDCDCmd::SDPSkipDCDCmd(char *p) : SDPCmdBase(p) { m_spdcmd.m_cmd = ROM_KERNEL_CMD_SKIP_DCD_HEADER; } int SDPSkipDCDCmd::run(CmdCtx*ctx) { HIDTrans dev; if (dev.open(ctx->m_dev)) return -1; HIDReport report(&dev); if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1)) return -1; if (check_ack(&report, ROM_OK_ACK)) return -1; return 0; } SDPBootCmd::SDPBootCmd(char *p) : SDPCmdBase(p) { insert_param_info("boot", nullptr, Param::Type::e_null); insert_param_info("-f", &m_filename, Param::Type::e_string_filename); insert_param_info("-nojump", &m_nojump, Param::Type::e_bool); insert_param_info("-cleardcd", &m_clear_dcd, Param::Type::e_bool); insert_param_info("-dcdaddr", &m_dcd_addr, Param::Type::e_uint32); insert_param_info("-scanlimited", &m_scan_limited, Param::Type::e_uint64); } int SDPBootCmd::run(CmdCtx *ctx) { string str; str = "SDP: dcd -f "; str += m_filename; if (m_dcd_addr) { str += " -dcdaddr "; str += std::to_string(m_dcd_addr); } if (m_scan_limited != UINT64_MAX) { str += " -scanlimited "; str += std::to_string(m_scan_limited); } SDPDcdCmd dcd((char *)str.c_str()); if (m_scan_limited != UINT64_MAX) { str += " -scanlimited "; str += std::to_string(m_scan_limited); } if (dcd.parser()) return -1; if (dcd.run(ctx)) return -1; str = "SDP: write -f "; str += m_filename; str += " -ivt 0"; if (m_scan_limited != UINT64_MAX) { str += " -scanlimited "; str += std::to_string(m_scan_limited); } SDPWriteCmd wr((char *)str.c_str()); if (wr.parser()) return -1; if (wr.run(ctx)) return -1; str = "SDP: jump -f "; str += m_filename; str += " -ivt 0"; if (m_clear_dcd) str += " -cleardcd"; if (m_scan_limited != UINT64_MAX) { str += " -scanlimited "; str += std::to_string(m_scan_limited); } SDPJumpCmd jmp((char *)str.c_str()); if (!m_nojump) { if (jmp.parser()) return -1; if (jmp.run(ctx)) return -1; } SDPBootlogCmd log(nullptr); log.run(ctx); return 0; } SDPStatusCmd::SDPStatusCmd(char *p) : SDPCmdBase(p) { m_spdcmd.m_cmd = ROM_KERNEL_CMD_ERROR_STATUS; insert_param_info("status", nullptr, Param::Type::e_null); } int SDPStatusCmd::run(CmdCtx *ctx) { HIDTrans dev; if (dev.open(ctx->m_dev)) return -1; HIDReport report(&dev); if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1)) return -1; if (get_hab_type(&report) == HabUnknown) return -1; uint32_t status; if (get_status(&report, status, 4)) return -1; return 0; } SDPWriteCmd::SDPWriteCmd(char *p) : SDPCmdBase(p) { m_spdcmd.m_cmd = ROM_KERNEL_CMD_WR_FILE; m_PlugIn = -1; m_Ivt = -1; m_max_download_pre_cmd = 0x200000; m_offset = 0; m_bIvtReserve = false; m_download_addr = 0; m_bskipspl = false; m_bscanterm = false; insert_param_info("write", nullptr, Param::Type::e_null); insert_param_info("-f", &m_filename, Param::Type::e_string_filename); insert_param_info("-ivt", &m_Ivt, Param::Type::e_uint32); insert_param_info("-addr", &m_download_addr, Param::Type::e_uint32); insert_param_info("-offset", &m_offset, Param::Type::e_uint32); insert_param_info("-skipspl", &m_bskipspl, Param::Type::e_bool); insert_param_info("-skipfhdr", &m_bskipfhdr, Param::Type::e_bool); insert_param_info("-scanterm", &m_bscanterm, Param::Type::e_bool); } int SDPWriteCmd::run(CmdCtx*ctx) { size_t size; uint8_t *pbuff; int offset = 0; shared_ptr fbuff, p1= get_file_buffer(m_filename, true); if (p1 == nullptr) return -1; fbuff = p1->request_data(0, m_scan_limited); if (m_Ivt < 0) { pbuff = fbuff->data(); size = fbuff->size(); offset = m_offset; if (m_bskipfhdr) offset += GetFlashHeaderSize(fbuff, offset); size_t pos = 0, length; if (m_bscanterm) { if (IsMBR(fbuff)) { length = ScanTerm(fbuff, pos); if (length == 0) { set_last_err_string("This wic have NOT terminate tag after bootloader, please use new yocto"); return -1; } offset = pos - length; if (offset < 0) { set_last_err_string("This wic boot length is wrong"); return -1; } size = pos; } } if (m_bskipspl) { const ROM_INFO * rom = search_rom_info(ctx->m_config_item); if(! (rom->flags & ROM_INFO_AUTO_SCAN_UBOOT_POS)) { set_last_err_string("SPL doesn't support auto scan uboot position"); return -1; } size_t off = offset; IvtHeader *pIvt = search_ivt_header(fbuff, off, 0x100000); if (pIvt) { BootData *pDB = (BootData *) &(fbuff->at(off + pIvt->BootData - pIvt->SelfAddr)); offset = off + pDB->ImageSize - (pIvt->SelfAddr - pDB->ImageStartAddr); } else { offset += GetContainerActualSize(fbuff, offset); } if (offset >= fbuff->m_avaible_size) { set_last_err_string("Unknown Image type, can't use skipspl format"); return -1; } } size -= offset; } else { size_t off = 0; IvtHeader *pIvt = search_ivt_header(fbuff, off); for (int i = 0; i < m_Ivt; i++) { off += sizeof(IvtHeader); pIvt = search_ivt_header(fbuff, off, m_scan_limited); } if (pIvt == nullptr) { set_last_err_string("Cannot find valid IVT header"); return -1; } BootData *pDB = (BootData *) &(fbuff->at(off + pIvt->BootData - pIvt->SelfAddr)); m_download_addr = pIvt->SelfAddr; //size = fbuff->size() - off; size = pDB->ImageSize - (pIvt->SelfAddr - pDB->ImageStartAddr); if (size >= m_scan_limited) { set_last_err_string("TODO: image is too big"); return -1; } //ImageSize may be bigger than Imagesize because ImageSize include IVT offset //Difference boot storage have difference IVT offset. if (size > fbuff->size() - off) size = fbuff->size() - off; pbuff = (uint8_t*)pIvt; } return run(ctx, pbuff + offset, size, m_download_addr); } int SDPWriteCmd::run(CmdCtx *ctx, void *pbuff, size_t size, uint32_t addr) { HIDTrans dev; if (dev.open(ctx->m_dev)) return -1; HIDReport report(&dev); report.set_notify_total(size); const ROM_INFO * rom = search_rom_info(ctx->m_config_item); size_t max = m_max_download_pre_cmd; /* SPL needn't split transfer */ if (rom && (rom ->flags & ROM_INFO_HID_SDP_NO_MAX_PER_TRANS)) max = size; for (size_t i=0; i < size; i += max) { size_t sz; sz = size - i; if (sz > max) sz = max; m_spdcmd.m_addr = EndianSwap((uint32_t)(addr + i)); // force use 32bit endian swap function; m_spdcmd.m_count = EndianSwap((uint32_t)sz); //force use 32bit endian swap function; report.set_position_base(i); report.set_skip_notify(true); if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1)) return -1; report.set_skip_notify(false); if (report.write(((uint8_t*)pbuff)+i, sz, 2)) return -1; if (check_ack(&report, ROM_STATUS_ACK)) return -1; } return 0; } SDPReadMemCmd::SDPReadMemCmd(char *p) : SDPCmdBase(p) { m_spdcmd.m_cmd = ROM_KERNEL_CMD_RD_MEM; insert_param_info("rdmem", nullptr, Param::Type::e_null); insert_param_info("-addr", &m_mem_addr, Param::Type::e_uint32); insert_param_info("-format", &m_mem_format, Param::Type::e_uint32); } int SDPReadMemCmd::run(CmdCtx *ctx) { HIDTrans dev; if (dev.open(ctx->m_dev)) return -1; HIDReport report(&dev); printf("\nReading address 0x%08X ...\n", m_mem_addr); m_spdcmd.m_addr = EndianSwap(m_mem_addr); m_spdcmd.m_format = m_mem_format; switch (m_mem_format) { case 0x8: m_spdcmd.m_count = EndianSwap((uint32_t)0x1); break; case 0x10: m_spdcmd.m_count = EndianSwap((uint32_t)0x2); break; case 0x20: m_spdcmd.m_count = EndianSwap((uint32_t)0x4); break; default: set_last_err_string("Invalid format, use <8|16|32>"); return -1; break; } if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1)) return -1; if (get_hab_type(&report) == HabUnknown) return -1; uint32_t mem_value; if (get_status(&report, mem_value, 4) == 0) { printf("\nValue of address 0x%08X: ", m_mem_addr); switch (m_mem_format) { case 0x8: printf("0x%02X\n", mem_value & 0xff); break; case 0x10: printf("0x%04X\n", mem_value & 0xffff); break; case 0x20: printf("0x%08X\n", mem_value); break; default: set_last_err_string("Invalid format, use <8|16|32>"); return -1; } } return 0; } SDPWriteMemCmd::SDPWriteMemCmd(char *p) : SDPCmdBase(p) { m_spdcmd.m_cmd = ROM_KERNEL_CMD_WR_MEM; insert_param_info("wrmem", nullptr, Param::Type::e_null); insert_param_info("-addr", &m_mem_addr, Param::Type::e_uint32); insert_param_info("-format", &m_mem_format, Param::Type::e_uint32); insert_param_info("-value", &m_mem_value, Param::Type::e_uint32); } int SDPWriteMemCmd::run(CmdCtx *ctx) { HIDTrans dev; if (dev.open(ctx->m_dev)) return -1; HIDReport report(&dev); printf("\nWriting 0x%08X to address 0x%08X ...\n", m_mem_value, m_mem_addr); m_spdcmd.m_addr = EndianSwap(m_mem_addr); m_spdcmd.m_format = m_mem_format; switch (m_mem_format) { case 0x8: m_spdcmd.m_count = EndianSwap((uint32_t)0x1); break; case 0x10: m_spdcmd.m_count = EndianSwap((uint32_t)0x2); break; case 0x20: m_spdcmd.m_count = EndianSwap((uint32_t)0x4); break; default: set_last_err_string("Invalid format, use <8|16|32>"); return -1; break; } m_spdcmd.m_data = EndianSwap(m_mem_value); if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1)) return -1; if (get_hab_type(&report) == HabUnknown) return -1; uint32_t status; if (get_status(&report, status, 4) < 0 || status != ROM_WRITE_ACK) { string_ex err; err.format("%s:%d Failed to write to address 0x%X", __FUNCTION__, __LINE__, m_mem_addr); set_last_err_string(err); } return 0; } SDPJumpCmd::SDPJumpCmd(char *p) : SDPCmdBase(p) { m_spdcmd.m_cmd = ROM_KERNEL_CMD_JUMP_ADDR; insert_param_info("jump", nullptr, Param::Type::e_null); insert_param_info("-f", &m_filename, Param::Type::e_string_filename); insert_param_info("-ivt", &m_Ivt, Param::Type::e_uint32); insert_param_info("-plugin", &m_PlugIn, Param::Type::e_bool); insert_param_info("-addr", &m_jump_addr, Param::Type::e_uint32); insert_param_info("-cleardcd", &m_clear_dcd, Param::Type::e_bool); } int SDPJumpCmd::run(CmdCtx *ctx) { const ROM_INFO * rom = search_rom_info(ctx->m_config_item); HIDTrans dev; if (dev.open(ctx->m_dev)) return -1; HIDReport report(&dev); if (rom == nullptr) { string_ex err; err.format("%s:%d can't get rom info", __FUNCTION__, __LINE__); set_last_err_string(err); return -1; } if (rom->flags & ROM_INFO_SPL_JUMP) { m_spdcmd.m_addr = EndianSwap(m_jump_addr); if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1)) return -1; //Omit last return value. check_ack(&report, ROM_OK_ACK); return 0; } shared_ptr buff, p1 = get_file_buffer(m_filename, true); if (!p1) return -1; buff = p1->request_data(0, m_scan_limited); size_t off = 0; IvtHeader *pIVT = search_ivt_header(buff, off, m_scan_limited); for (int i = 0; i < m_Ivt; i++) { off += sizeof(IvtHeader); pIVT = search_ivt_header(buff, off); } if (pIVT == nullptr) { set_last_err_string("Cannot find valid IVT header"); return -1; } m_spdcmd.m_addr = EndianSwap(pIVT->SelfAddr); if (rom->flags & ROM_INFO_HID_SKIP_DCD && !m_clear_dcd) { SDPSkipDCDCmd skipcmd(nullptr); if (skipcmd.run(ctx)) return -1; } else { /*Clear DCD*/ vector ivt; /* Need send out whole report size buffer avoid overwrite other data * Some platform require receive whole package for report id = 2 */ ivt.resize(report.get_out_package_size()); size_t sz = buff->size(); sz -= (uint8_t*)pIVT - (uint8_t*)buff->data(); if (sz > ivt.size()) sz = ivt.size(); memcpy(ivt.data(), pIVT, sz); IvtHeader *header = (IvtHeader *)ivt.data(); header->DCDAddress = 0; SDPWriteCmd writecmd(nullptr); if(writecmd.run(ctx, header, ivt.size(), pIVT->SelfAddr)) return -1; } if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1)) return -1; //Omit last return value. check_ack(&report, ROM_OK_ACK); return 0; } SDPBootlogCmd::SDPBootlogCmd(char *p) : SDPCmdBase(p) { insert_param_info("blog", nullptr, Param::Type::e_null); } int SDPBootlogCmd::run(CmdCtx *ctx) { HIDTrans dev{2000}; if (dev.open(ctx->m_dev)) return -1; HIDReport report(&dev); vector v(65); v[0] = 'I'; uuu_notify nt; nt.type = uuu_notify::NOTIFY_CMD_INFO; int ret; while (1) { ret = report.read(v); if (ret) return 0; else { nt.str = (char*)(v.data() + 4); v[5] = 0; call_notify(nt); continue; } } return 0; } mfgtools-uuu_1.4.193/libuuu/sdp.h000066400000000000000000000115151417203213400166650ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include "cmd.h" #include class FileBuffer; class HIDReport; #pragma pack (1) struct SDPCmd { uint16_t m_cmd; uint32_t m_addr; uint8_t m_format; uint32_t m_count; uint32_t m_data; uint8_t m_rsvd; }; struct IvtHeader { uint32_t IvtBarker; uint32_t ImageStartAddr; uint32_t Reserved; uint32_t DCDAddress; uint32_t BootData; uint32_t SelfAddr; uint32_t Reserved2[2]; }; struct BootData { uint32_t ImageStartAddr; uint32_t ImageSize; uint32_t PluginFlag; }; #pragma pack () #define ROM_KERNEL_CMD_RD_MEM 0x0101 #define ROM_KERNEL_CMD_WR_MEM 0x0202 #define ROM_KERNEL_CMD_WR_FILE 0x0404 #define ROM_KERNEL_CMD_ERROR_STATUS 0x0505 #define RAM_KERNEL_CMD_HEADER 0x0606 //#define ROM_KERNEL_CMD_RE_ENUM 0x0909 #define ROM_KERNEL_CMD_DCD_WRITE 0x0A0A #define ROM_KERNEL_CMD_JUMP_ADDR 0x0B0B #define ROM_KERNEL_CMD_SKIP_DCD_HEADER 0x0C0C #define MAX_DCD_WRITE_REG_CNT 85 #define ROM_WRITE_ACK 0x128A8A12 #define ROM_STATUS_ACK 0x88888888 #define ROM_OK_ACK 0x900DD009 #define IVT_BARKER_HEADER 0x402000D1 #define IVT_BARKER2_HEADER 0x412000D1 #define HAB_TAG_DCD 0xd2 /**< Device Configuration Data */ class SDPCmdBase:public CmdBase { public: enum HAB_t { HabUnknown = -1, HabEnabled = 0x12343412, HabDisabled = 0x56787856 }; SDPCmdBase(char *p) :CmdBase(p) { init_cmd(); } protected: int check_ack(HIDReport *report, uint32_t ack); HAB_t get_hab_type(HIDReport *report); int get_status(HIDReport *p, uint32_t &status, uint8_t report_id); int init_cmd(); IvtHeader * search_ivt_header(std::shared_ptr data, size_t &off, size_t limit=ULLONG_MAX); std::string m_filename; SDPCmd m_spdcmd; uint64_t m_scan_limited = UINT64_MAX; private: int send_cmd(HIDReport *p); std::vector m_input; }; class SDPBootlogCmd : public SDPCmdBase { public: SDPBootlogCmd(char *p); int run(CmdCtx *) override; }; class SDPDcdCmd : public SDPCmdBase { public: SDPDcdCmd(char *p); int run(CmdCtx *) override; private: uint32_t m_dcd_addr; }; class SDPReadMemCmd : public SDPCmdBase { public: SDPReadMemCmd(char*p); int run(CmdCtx *) override; private: uint32_t m_mem_addr; uint8_t m_mem_format; }; class SDPWriteMemCmd : public SDPCmdBase { public: SDPWriteMemCmd(char*p); int run(CmdCtx *p) override; private: uint32_t m_mem_addr; uint8_t m_mem_format; uint32_t m_mem_value; }; class SDPWriteCmd : public SDPCmdBase { public: SDPWriteCmd(char*p); int run(CmdCtx *p) override; int run(CmdCtx *p, void *buff, size_t size, uint32_t addr); private: uint32_t m_download_addr; int32_t m_Ivt; int m_PlugIn; uint32_t m_max_download_pre_cmd; uint32_t m_offset; bool m_bIvtReserve; bool m_bskipspl = false; bool m_bskipfhdr = false; bool m_bscanterm = false; }; class SDPJumpCmd : public SDPCmdBase { public: SDPJumpCmd(char*p); int run(CmdCtx *p) override; private: bool m_clear_dcd = false; int32_t m_Ivt = -1; uint32_t m_jump_addr = 0; bool m_PlugIn = false; }; class SDPSkipDCDCmd :public SDPCmdBase { public: SDPSkipDCDCmd(char *p); int run(CmdCtx *p) override; }; class SDPStatusCmd :public SDPCmdBase { public: SDPStatusCmd(char *p); int run(CmdCtx *p) override; }; class SDPBootCmd : public SDPCmdBase { public: SDPBootCmd(char *p); int run(CmdCtx *p) override; private: bool m_clear_dcd = false; uint32_t m_dcd_addr = 0; bool m_nojump = false; }; mfgtools-uuu_1.4.193/libuuu/sdps.cpp000066400000000000000000000120301417203213400173740ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include "sdps.h" #include "hidreport.h" #include "liberror.h" #include "libcomm.h" #include "buffer.h" #include "sdp.h" #include "trans.h" #include //------------------------------------------------------------------------------ // HID Command Block Wrapper (CBW) //------------------------------------------------------------------------------ #pragma pack (1) typedef struct _CDBHIDDOWNLOAD { uint8_t Command; uint32_t Length; uint8_t Reserved[11]; } CDBHIDDOWNLOAD, *PCDBHIDDOWNLOAD; struct _ST_HID_CBW { uint32_t Signature; // Signature: 0x43544C42:1129598018, o "BLTC" (little endian) for the BLTC CBW uint32_t Tag; // Tag: to be returned in the csw uint32_t XferLength; // XferLength: number of bytes to transfer uint8_t Flags; // Flags: // Bit 7: direction - device shall ignore this bit if the // XferLength field is zero, otherwise: // 0 = data-out from the host to the device, // 1 = data-in from the device to the host. // Bits 6..0: reserved - shall be zero. uint8_t Reserved[2]; // Reserved - shall be zero. CDBHIDDOWNLOAD Cdb; // cdb: the command descriptor block }; #define BLTC_DOWNLOAD_FW 2 #define HID_BLTC_REPORT_TYPE_DATA_OUT 2 #define HID_BLTC_REPORT_TYPE_COMMAND_OUT 1 #define CBW_BLTC_SIGNATURE 0x43544C42; // "BLTC" (little endian) #define CBW_PITC_SIGNATURE 0x43544950; // "PITC" (little endian) // Flags values for _ST_HID_CBW #define CBW_DEVICE_TO_HOST_DIR 0x80; // "Data Out" #define CBW_HOST_TO_DEVICE_DIR 0x00; // "Data In" #pragma pack () #include "rominfo.h" int SDPSCmd::run(CmdCtx *pro) { const ROM_INFO * rom = search_rom_info(pro->m_config_item); if (rom == nullptr) { string_ex err; err.format("%s:%d can't get rom info", __FUNCTION__, __LINE__); set_last_err_string(err); return -1; } HIDTrans dev; if (rom->flags & ROM_INFO_HID_EP1) dev.set_hid_out_ep(1); if(dev.open(pro->m_dev)) return -1; shared_ptr p, p1 = get_file_buffer(m_filename, true); if (!p1) return -1; HIDReport report(&dev); report.set_skip_notify(false); size_t offset = m_offset; vector buff; if (m_bscanterm) { p = p1->request_data(0, m_scan_limited); if (IsMBR(p)) { size_t pos = 0, length; length = ScanTerm(p, pos, 512, m_scan_limited); if (length == 0) { set_last_err_string("This wic have NOT terminate tag after bootloader, please use new yocto"); return -1; } offset = pos - length; if (offset < 0) { set_last_err_string("This wic boot length is wrong"); return -1; } p->resize(pos); } } else { p = get_file_buffer(m_filename); //request all data } if (m_bskipflashheader) offset += GetFlashHeaderSize(p, offset); if (offset >= p->size()) { set_last_err_string("Offset bigger than file size"); return -1; } size_t sz = GetContainerActualSize(p, offset, rom->flags & ROM_INFO_HID_ROMAPI); if (!(rom->flags & ROM_INFO_HID_NO_CMD)) { _ST_HID_CBW cbw; uint32_t length = (uint32_t) sz; memset(&cbw, 0, sizeof(_ST_HID_CBW)); cbw.Cdb.Command = BLTC_DOWNLOAD_FW; cbw.Cdb.Length = EndianSwap(length); ++cbw.Tag; cbw.Signature = CBW_BLTC_SIGNATURE; cbw.XferLength = (uint32_t)length; cbw.Flags = CBW_HOST_TO_DEVICE_DIR; int ret = report.write(&cbw, sizeof(_ST_HID_CBW), HID_BLTC_REPORT_TYPE_COMMAND_OUT); if (ret) return ret; } if (rom->flags & ROM_INFO_HID_PACK_SIZE_1020) report.set_out_package_size(1020); int ret = report.write(p->data() + offset, sz, 2); if (ret == 0) { SDPBootlogCmd log(nullptr); log.run(pro); } return ret; } mfgtools-uuu_1.4.193/libuuu/sdps.h000066400000000000000000000042251417203213400170500ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "cmd.h" class SDPSCmd : public CmdBase { public: SDPSCmd(char *cmd) :CmdBase(cmd) { insert_param_info("boot", nullptr, Param::Type::e_null); insert_param_info("-f", &m_filename, Param::Type::e_string_filename); insert_param_info("-offset", &m_offset, Param::Type::e_uint32); insert_param_info("-skipfhdr", &m_bskipflashheader, Param::Type::e_bool); insert_param_info("-scanterm", &m_bscanterm, Param::Type::e_bool); insert_param_info("-scanlimited", &m_scan_limited, Param::Type::e_uint64); } int run(CmdCtx *p) override; private: bool m_bskipflashheader=0; bool m_bscanterm=0; std::string m_filename; uint32_t m_offset = 0; uint64_t m_scan_limited = UINT64_MAX; }; mfgtools-uuu_1.4.193/libuuu/sparse.cpp000066400000000000000000000131251417203213400177260ustar00rootroot00000000000000/* * Copyright 2020 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "sparse.h" #include "liberror.h" #include #include chunk_header_t * SparseFile::get_next_chunk(uint8_t *p, size_t &pos) { if (pos == 0) { sparse_header *pheader = (sparse_header*)p; if (pheader->magic != SPARSE_HEADER_MAGIC) { set_last_err_string("Sparse heade Magic missed"); return nullptr; } pos += pheader->file_hdr_sz; } chunk_header_t *pchunk = (chunk_header_t*)(p + pos); pos += pchunk->total_sz; return pchunk; } int SparseFile::init_header(size_t blsz, int blcount) { sparse_header header; memset(&header, 0, sizeof(header)); header.magic = SPARSE_HEADER_MAGIC; header.major_version = 1; header.minor_version = 0; header.file_hdr_sz = sizeof(header); header.chunk_hdr_sz = sizeof(chunk_header); header.blk_sz = blsz; m_cur_chunk_header_pos = 0; if (blcount) { m_data.reserve(blsz*blcount + 0x1000); m_max_size = blsz * blcount; } m_data.clear(); push(&header, sizeof(header)); m_pcrc = (uint32_t*)(m_data.data() + offsetof(sparse_header, image_checksum)); return 0; } bool SparseFile::is_append_old_chuck(int type, void *p) { chunk_header_t *pchunk; pchunk = (chunk_header_t *)(m_data.data() + m_cur_chunk_header_pos); if (m_cur_chunk_header_pos == 0) return false; if (pchunk->chunk_type != type) return false; if (type == CHUNK_TYPE_FILL) { uint32_t a = *(uint32_t*)(pchunk + 1); uint32_t b = *(uint32_t*)p; if (a != b) return false; } return true; } bool SparseFile::is_same_value(void *data, size_t sz) { uint32_t *p = (uint32_t *)data; uint32_t val = *p; for (size_t i = 0; i < sz / sizeof(uint32_t); i++) if (val != p[i]) return false; return true; } bool SparseFile::is_validate_sparse_file(void *p, size_t) { sparse_header *pheader = (sparse_header*)p; if (pheader->magic == SPARSE_HEADER_MAGIC) return true; return false; } int SparseFile::push(void *p, size_t sz) { size_t pos = m_data.size(); m_data.resize(pos + sz); memcpy(m_data.data() + pos, p, sz); return 0; } int SparseFile::push_one_block(void *data) { chunk_header_t *pchunk; pchunk = (chunk_header_t *)(m_data.data() + m_cur_chunk_header_pos); sparse_header *pheader; pheader = (sparse_header *)m_data.data(); pheader->total_blks++; //int type = is_same_value(data, pheader->blk_sz) ? CHUNK_TYPE_FILL : CHUNK_TYPE_RAW; int type = CHUNK_TYPE_RAW; if (!is_append_old_chuck(type, data)) { chunk_header_t header; header.chunk_type = type; header.chunk_sz = 1; header.total_sz = (type == CHUNK_TYPE_FILL) ? sizeof(uint32_t) : pheader->blk_sz; header.total_sz += sizeof(chunk_header_t); header.reserved1 = 0; pheader->total_chunks++; m_cur_chunk_header_pos = m_data.size(); push(&header, sizeof(chunk_header_t)); if (type == CHUNK_TYPE_RAW) push(data, pheader->blk_sz); else push(data, sizeof(uint32_t)); } else { pchunk->chunk_sz++; if (type == CHUNK_TYPE_RAW) { push(data, pheader->blk_sz); pchunk->total_sz += pheader->blk_sz; } } if (m_data.size() + 2 * pheader->blk_sz > m_max_size ) return -1; return 0; } size_t SparseFile::push_one_chuck(chunk_header_t *p, void *data) { chunk_header_t cheader = *p; sparse_header *pheader; pheader = (sparse_header *)m_data.data(); size_t sz = p->total_sz - sizeof(chunk_header); if (p->total_sz + m_data.size() > m_max_size) { if (p->chunk_type == CHUNK_TYPE_RAW) { size_t blk = (m_max_size - m_data.size()) / pheader->blk_sz; if (blk < 2) return 0; blk -= 2; cheader.chunk_sz = blk; sz = blk * pheader->blk_sz; cheader.total_sz = sizeof(chunk_header_t) + sz; } else return 0; } push(&cheader, sizeof(chunk_header)); pheader->total_chunks ++; pheader->total_blks += cheader.chunk_sz; if (data) { push(data, sz); } return sz; } size_t SparseFile::push_raw_data(void *data, size_t sz) { chunk_header_t cheader; cheader.chunk_type = CHUNK_TYPE_RAW; sparse_header *pheader; pheader = (sparse_header *)m_data.data(); cheader.chunk_sz = sz / pheader->blk_sz; cheader.total_sz = cheader.chunk_sz*pheader->blk_sz + sizeof(chunk_header_t); pheader = (sparse_header *)m_data.data(); return push_one_chuck(&cheader, data); } mfgtools-uuu_1.4.193/libuuu/sparse.h000066400000000000000000000041421417203213400173720ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include "sparse_format.h" #include #include class SparseFile { public: std::vector m_data; static chunk_header_t * get_next_chunk(uint8_t *p, size_t &pos); int init_header(size_t blsz, int blcount); bool is_append_old_chuck(int type, void *p); bool is_same_value(void *data, size_t sz); static bool is_validate_sparse_file(void *p, size_t sz); int push(void *p, size_t sz); int push_one_block(void *data); size_t push_one_chuck(chunk_header_t *p, void *data); size_t push_raw_data(void *data, size_t sz); private: size_t m_cur_chunk_header_pos; size_t m_max_size; uint32_t *m_pcrc; }; mfgtools-uuu_1.4.193/libuuu/sparse_format.h000066400000000000000000000045341417203213400207470ustar00rootroot00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * 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 _LIBSPARSE_SPARSE_FORMAT_H_ #define _LIBSPARSE_SPARSE_FORMAT_H_ #include typedef uint32_t __le32; typedef uint16_t __le16; #pragma pack(1) typedef struct sparse_header { __le32 magic; /* 0xed26ff3a */ __le16 major_version; /* (0x1) - reject images with higher major versions */ __le16 minor_version; /* (0x0) - allow images with higer minor versions */ __le16 file_hdr_sz; /* 28 bytes for first revision of the file format */ __le16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */ __le32 blk_sz; /* block size in bytes, must be a multiple of 4 (4096) */ __le32 total_blks; /* total blocks in the non-sparse output image */ __le32 total_chunks; /* total chunks in the sparse input image */ __le32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" */ /* as 0. Standard 802.3 polynomial, use a Public Domain */ /* table implementation */ } sparse_header_t; #define SPARSE_HEADER_MAGIC 0xed26ff3a #define CHUNK_TYPE_RAW 0xCAC1 #define CHUNK_TYPE_FILL 0xCAC2 #define CHUNK_TYPE_DONT_CARE 0xCAC3 #define CHUNK_TYPE_CRC32 0xCAC4 typedef struct chunk_header { __le16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */ __le16 reserved1; __le32 chunk_sz; /* in blocks in output image */ __le32 total_sz; /* in bytes of chunk input file including chunk header and data */ } chunk_header_t; /* Following a Raw or Fill or CRC32 chunk is data. * For a Raw chunk, it's the data in chunk_sz * blk_sz. * For a Fill chunk, it's 4 bytes of the fill data. * For a CRC32 chunk, it's 4 bytes of CRC32 */ #pragma pack() #endif mfgtools-uuu_1.4.193/libuuu/tar.cpp000066400000000000000000000075651417203213400172320ustar00rootroot00000000000000/* * Copyright 2020 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include "zlib.h" #include #include "buffer.h" #include "liberror.h" #include "libuuu.h" #include #include #include "tar.h" #include #include using namespace std; int Tar::Open(const string &filename) { bool end_of_file=false; char end_of_file_blocks[2*TAR_BLOCK_SIZE]; memset(end_of_file_blocks, 0, sizeof(end_of_file_blocks) ); m_tarfilename=filename; shared_ptr file = get_file_buffer(filename); if(file == nullptr) return -1; uint8_t* data=file->data(); uint64_t block_counter=0; while(!end_of_file) { if(!memcmp(end_of_file_blocks,data+block_counter*TAR_BLOCK_SIZE,TAR_BLOCK_SIZE)) { end_of_file=true; break; } struct Tar_header* th=(Tar_header*)(data+block_counter*TAR_BLOCK_SIZE); uint64_t size; string octal_str((char*)th->size); //printf("block_counter: %d\n",block_counter ); //printf("name: %s\n",th->name ); //printf("signature: %s\n",th->ustar ); //printf("size: %s\n", th->size); size=stoll(octal_str, 0, 8); string name((char*)th->name); m_filemap[name].size=size; m_filemap[name].offset=(block_counter+1)*TAR_BLOCK_SIZE; //+1 because the data located right after the header block m_filemap[name].filename.assign((char*)th->name); block_counter++; //skip the data blocks uint64_t data_block_num=size/TAR_BLOCK_SIZE; data_block_num += (size%TAR_BLOCK_SIZE>0)? 1:0; block_counter+=data_block_num; } return 0; } bool Tar::check_file_exist(const string &filename) { if (m_filemap.find(filename) == m_filemap.end()) { string err; err += "Can't find file "; err += filename; set_last_err_string(err); return false; } return true; } int Tar::get_file_buff(const string &filename, shared_ptr p ) { if (m_filemap.find(filename) == m_filemap.end()) { string err; err += "Can't find file "; err += filename; set_last_err_string(err); return -1; } p->resize(m_filemap[filename].size); atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_KNOWN_SIZE); p->m_request_cv.notify_all(); shared_ptr file; file = get_file_buffer(m_tarfilename); size_t offset= m_filemap[filename].offset; size_t size=m_filemap[filename].size; p->ref_other_buffer(file, offset, size); atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); return 0; } mfgtools-uuu_1.4.193/libuuu/tar.h000066400000000000000000000045621417203213400166710ustar00rootroot00000000000000/* * Copyright 2020 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include #include #include #include class FileBuffer; #define TAR_BLOCK_SIZE 512 #pragma pack(1) struct Tar_header { uint8_t name[100]; uint8_t mode[8]; uint8_t owner_id[8]; uint8_t group_id[8]; uint8_t size[12]; uint8_t modi_time[12]; uint8_t checksum[8]; uint8_t type[1]; uint8_t linkname[100]; uint8_t ustar[6]; uint8_t version[2]; uint8_t uname[32]; uint8_t gname[32]; uint8_t major_num[8]; uint8_t minor_num[8]; uint8_t prefix[155]; }; #pragma pack() class Tar_file_Info { public: std::string filename; uint64_t offset; uint64_t size; }; class Tar { std::string m_tarfilename; public: std::map m_filemap; int Open(const std::string &filename); bool check_file_exist(const std::string &filename); int get_file_buff(const std::string &filename, std::shared_ptr p); }; mfgtools-uuu_1.4.193/libuuu/trans.cpp000066400000000000000000000135201417203213400175570ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "trans.h" #include "libuuu.h" #include "liberror.h" #include "libusb.h" extern "C" { #include "libusb.h" } using namespace std; TransBase::~TransBase() { } int TransBase::read(vector &buff) { size_t size; const auto ret = read(buff.data(), buff.size(), &size); if (ret) return ret; buff.resize(size); return ret; } int USBTrans::open(void *p) { m_devhandle = p; libusb_device_handle * handle = (libusb_device_handle *)m_devhandle; if (libusb_kernel_driver_active(handle, 0)) { int ret = libusb_detach_kernel_driver((libusb_device_handle *)m_devhandle, 0); if(ret <0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) { set_last_err_string("detach kernel driver failure"); return -1; } } if (libusb_claim_interface(handle, 0)) { set_last_err_string("Failure claim interface"); return -1; } libusb_config_descriptor *config; if (libusb_get_active_config_descriptor(libusb_get_device(handle), &config)) { set_last_err_string("Can't get config descriptor"); return -1; } m_EPs.clear(); for (int i = 0; i < config->interface[0].altsetting[0].bNumEndpoints; i++) { m_EPs.push_back(EPInfo(config->interface[0].altsetting[0].endpoint[i].bEndpointAddress, config->interface[0].altsetting[0].endpoint[i].wMaxPacketSize)); }; libusb_free_config_descriptor(config); return 0; } int USBTrans::close() { /* needn't clean resource here libusb_close will release all resource when finish running cmd */ return 0; } int HIDTrans::open(void *p) { if (USBTrans::open(p)) return -1; for (const auto &ep : m_EPs) { if (ep.addr > 0 && ((ep.addr & 0x80) == 0)) m_outEP = ep.addr; } return 0; } int HIDTrans::write(void *buff, size_t size) { int ret; uint8_t *p = (uint8_t *)buff; int actual_size; if (m_outEP) { ret = libusb_interrupt_transfer( (libusb_device_handle *)m_devhandle, m_outEP, p, size, &actual_size, 1000 ); } else { ret = libusb_control_transfer( (libusb_device_handle *)m_devhandle, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, m_set_report, (2 << 8) | p[0], 0, p, size, 1000 ); } if (ret < 0) { string err; err = "HID(W):"; err += libusb_error_name(ret); set_last_err_string(err); return ret; } return ret; } int HIDTrans::read(void *buff, size_t size, size_t *rsize) { int ret; int actual; ret = libusb_interrupt_transfer( (libusb_device_handle *)m_devhandle, 0x81, (uint8_t*)buff, size, &actual, m_read_timeout ); *rsize = actual; if (ret < 0) { string error; string err; err = "HID(R):"; err += libusb_error_name(ret); set_last_err_string(err); return ret; } return 0; } int BulkTrans::write(void *buff, size_t size) { int ret; int actual_lenght; for (size_t i = 0; i < size; i += m_MaxTransPreRequest) { uint8_t *p = (uint8_t *)buff; p += i; size_t sz; sz = size - i; if (sz > m_MaxTransPreRequest) sz = m_MaxTransPreRequest; ret = libusb_bulk_transfer( (libusb_device_handle *)m_devhandle, m_ep_out.addr, p, sz, &actual_lenght, m_timeout ); if (ret < 0) { string error; string err; err = "Bulk(W):"; err += libusb_error_name(ret); set_last_err_string(err); return ret; } } //Send zero package if (m_b_send_zero && ( (size%m_ep_out.package_size) == 0)) { ret = libusb_bulk_transfer( (libusb_device_handle *)m_devhandle, m_ep_out.addr, nullptr, 0, &actual_lenght, 2000 ); if (ret < 0) { string error; string err; err = "Bulk(W):"; err += libusb_error_name(ret); set_last_err_string(err); return ret; } } return ret; } int BulkTrans::open(void *p) { if (USBTrans::open(p)) return -1; for (size_t i = 0; i < m_EPs.size(); i++) { if (m_EPs[i].addr > 0) { if ((m_EPs[0].addr & 0x80) && m_ep_in.addr == 0) m_ep_in = m_EPs[i]; else if (m_ep_out.addr == 0) m_ep_out = m_EPs[i]; } } return 0; } int BulkTrans::read(void *buff, size_t size, size_t *rsize) { int ret; int actual_lenght; uint8_t *p = (uint8_t *)buff; if (size == 0) { *rsize = 0; return 0; } ret = libusb_bulk_transfer( (libusb_device_handle *)m_devhandle, m_ep_in.addr, p, size, &actual_lenght, m_timeout ); *rsize = actual_lenght; if (ret < 0) { string error; string err; err = "Bulk(R):"; err += libusb_error_name(ret); set_last_err_string(err); return ret; } return ret; } mfgtools-uuu_1.4.193/libuuu/trans.h000066400000000000000000000064631417203213400172340ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include #include #include class TransBase { public: TransBase() = default; TransBase(const TransBase&) = delete; TransBase& operator=(const TransBase&) = delete; virtual ~TransBase(); virtual int open(void *) { return 0; } virtual int close() { return 0; } virtual int write(void *buff, size_t size) = 0; virtual int read(void *buff, size_t size, size_t *return_size) = 0; int write(std::vector & buff) { return write(buff.data(), buff.size()); } int read(std::vector &buff); protected: void * m_devhandle = nullptr; }; class EPInfo { public: constexpr EPInfo() = default; constexpr EPInfo(int a, int size) : addr{a}, package_size{size} {} int addr = 0; int package_size = 64; }; class USBTrans : public TransBase { public: int open(void *p) override; int close() override; protected: std::vector m_EPs; }; class HIDTrans : public USBTrans { public: HIDTrans(int read_timeout = 1000) : m_read_timeout{read_timeout} {} ~HIDTrans() override { if (m_devhandle) close(); m_devhandle = nullptr; } int open(void *p) override; void set_hid_out_ep(int ep) noexcept { m_outEP = ep; } int write(void *buff, size_t size) override; int read(void *buff, size_t size, size_t *return_size) override; private: int m_outEP = 0; const int m_read_timeout = 1000; int m_set_report = 9; }; class BulkTrans : public USBTrans { public: BulkTrans(uint64_t timeout = 2000) : m_timeout{timeout} {} ~BulkTrans() override { if (m_devhandle) close(); m_devhandle = nullptr; } int open(void *p) override; int write(void *buff, size_t size) override; int read(void *buff, size_t size, size_t *return_size) override; private: size_t m_MaxTransPreRequest = 0x100000; int m_b_send_zero = 0; EPInfo m_ep_in; EPInfo m_ep_out; uint64_t m_timeout = 2000; }; int polling_usb(std::atomic& bexit); mfgtools-uuu_1.4.193/libuuu/usbhotplug.cpp000066400000000000000000000262631417203213400206340ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ /* * Windows libusb don't support hotplug yet * Will polling devices list every 100ms */ #include #include #include #include #include #include #include "libusb.h" #include "liberror.h" #include "config.h" #include "cmd.h" #include "libcomm.h" #include "libuuu.h" #include "vector" #include using chrono::milliseconds; using chrono::operator ""ms; using chrono::seconds; using chrono::operator ""s; static atomic g_wait_usb_timeout{-1s}; static atomic g_usb_poll_period{200ms}; static atomic g_wait_next_usb_timeout{-1s}; enum KnownDeviceState { NoKnownDevice, KnownDeviceToDo, KnownDeviceDone, WaitNextKnownDevice, }; static atomic g_known_device_state{NoKnownDevice}; class CAutoDeInit { public: CAutoDeInit() { if (libusb_init(nullptr) < 0) throw runtime_error{ "Call libusb_init failure" }; } ~CAutoDeInit() { libusb_exit(nullptr); } } g_autoDeInit; class CAutoList { public: libusb_device **list = nullptr; CAutoList(libusb_device **list) { this->list = list; m_rc = -1; } CAutoList(CAutoList &&other) { this->list = other.list; this->m_rc = other.m_rc; other.list = nullptr; } CAutoList() { m_rc = libusb_get_device_list(nullptr, &list); if (m_rc < 0) { set_last_err_string(std::string("libusb_get_device_list failed: ") + libusb_strerror(static_cast(m_rc))); } } ~CAutoList() { if (list != nullptr) { libusb_free_device_list(list, 1); } } CAutoList& operator=(CAutoList &&other) { this->list = other.list; this->m_rc = other.m_rc; other.list = nullptr; return *this; } CAutoList& operator=(const CAutoList&) = delete; // Prevent copy, allow move only CAutoList(const CAutoList&) = delete; // Prevent copy, allow move only bool good() const { return m_rc >= 0; } private: int m_rc = 0; }; static struct { vector list; mutex lock; void push_back(string filter) { lock_guard guard{lock}; list.emplace_back(move(filter)); } bool is_valid(const string& path) { lock_guard guard{lock}; if (list.empty()) return true; auto end = list.end(); auto pos = find(list.begin(), end, path); return pos != end; } } g_filter_usbpath; struct Timer { using Clock = chrono::steady_clock; Clock::time_point start; explicit Timer(Clock::time_point start) : start{start} {} Timer() : Timer{Clock::now()} {} bool is_elapsed(Clock::duration interval) const { return (Clock::now() - start) >= interval; } void reset(Clock::time_point start) { this->start = start; } void reset() { reset(Clock::now()); } }; #ifdef _MSC_VER #define TRY_SUDO #else #define TRY_SUDO ",Try sudo uuu" #endif static string get_device_path(libusb_device *dev) { uint8_t path[8]; int bus = libusb_get_bus_number(dev); string_ex str; str.format("%d:", bus); int ret = libusb_get_port_numbers(dev, path, sizeof(path)); if (ret < 0) return ""; string_ex s; s.format("%d", path[0]); str.append(s); for (int j = 1; j < ret; j++) { s.format("%d", path[j]); str.append(s); } return str; } static int open_libusb(libusb_device *dev, void **usb_device_handle) { int retry = 1; #ifdef WIN32 retry = 5; #endif while (retry) { retry--; /* work around windows open device failure 1/10 * sometime HID device detect need some time, refresh list * to make sure HID driver installed. */ CAutoList l; int ret; if ((ret = libusb_open(dev, (libusb_device_handle **)(usb_device_handle))) < 0) { if ((ret != LIBUSB_ERROR_NOT_SUPPORTED) || (retry == 0)) { set_last_err_string("Failure open usb device" TRY_SUDO); return -1; } this_thread::sleep_for(200ms); } else { return 0; } } return -1; } /** Thread function. Didn't call this function directly. Unbalance libusb_unref_device. Before start thread, need call libusb_ref_device to dev is free libusb_get_list() libusb_ref_devive // avoid free at libusb_free_list if run_usb_cmd have not open device in time. thread start run_usb_cmds; libusb_free_list() */ static int run_usb_cmds(ConfigItem *item, libusb_device *dev, short bcddevice) { int ret; uuu_notify nt; nt.type = uuu_notify::NOFITY_DEV_ATTACH; string str; str = get_device_path(dev); nt.str = (char*)str.c_str(); call_notify(nt); CmdUsbCtx ctx; ctx.m_config_item = item; ctx.m_current_bcd = bcddevice; if (ret = open_libusb(dev, &(ctx.m_dev))) { nt.type = uuu_notify::NOTIFY_CMD_END; nt.status = -1; call_notify(nt); return ret; } ret = run_cmds(item->m_protocol.c_str(), &ctx); g_known_device_state = KnownDeviceDone; nt.type = uuu_notify::NOTIFY_THREAD_EXIT; call_notify(nt); libusb_unref_device(dev); //ref_device when start thread clear_env(); return ret; } static int usb_add(libusb_device *dev) { struct libusb_device_descriptor desc; int r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { set_last_err_string("failure get device descrior"); return r; } string str; str = get_device_path(dev); if (!g_filter_usbpath.is_valid(str)) return -1; ConfigItem *item = get_config()->find(desc.idVendor, desc.idProduct, desc.bcdDevice); this_thread::sleep_for(g_usb_poll_period.load()); if (item) { g_known_device_state = KnownDeviceToDo; /* * start new thread, need increase dev ref number. * otherwise polling thread, free_device_list free device if open device call after free_device_list. */ libusb_ref_device(dev); std::thread(run_usb_cmds, item, dev, desc.bcdDevice).detach(); } return 0; } static int usb_remove(libusb_device * /*dev*/) { return 0; } void compare_list(libusb_device ** old, libusb_device **nw) { libusb_device * dev; int i = 0; if (old == nullptr) { while ((dev = nw[i++]) != nullptr) { usb_add(dev); } return; } while ((dev = nw[i++]) != nullptr) { libusb_device * p; int j = 0; while ((p = old[j++]) != nullptr) { if (p == dev) break;//find it. }; if (p != dev) usb_add(dev); } i = 0; while ((dev = old[i++]) != nullptr) { libusb_device * p; int j = 0; while ((p = nw[j++]) != nullptr) { if (p == dev) break;//find it. }; if (p != dev) usb_remove(dev); } } static int check_usb_timeout(Timer& usb_timer) { auto known_device_state = g_known_device_state.load(); if (known_device_state == KnownDeviceDone) { g_known_device_state = known_device_state = WaitNextKnownDevice; usb_timer.reset(); } auto usb_timeout = g_wait_usb_timeout.load(); if (usb_timeout >= 0s && known_device_state == NoKnownDevice) { if (usb_timer.is_elapsed(usb_timeout)) { set_last_err_string("Timeout: Wait for Known USB Device"); return -1; } } usb_timeout = g_wait_next_usb_timeout.load(); if (usb_timeout >= 0s && g_known_device_state == WaitNextKnownDevice) { if (usb_timer.is_elapsed(usb_timeout)) { set_last_err_string("Timeout: Wait for next USB Device"); return -1; } } return 0; } int polling_usb(std::atomic& bexit) { if (run_cmds("CFG:", nullptr)) return -1; Timer usb_timer; CAutoList oldlist(nullptr); while(!bexit) { CAutoList newlist; if (!newlist.good()) { return -1; } compare_list(oldlist.list, newlist.list); std::swap(oldlist, newlist); this_thread::sleep_for(g_usb_poll_period.load()); if (check_usb_timeout(usb_timer)) return -1; } return 0; } CmdUsbCtx::~CmdUsbCtx() { if (m_dev) { libusb_close((libusb_device_handle*)m_dev); m_dev = 0; } } int CmdUsbCtx::look_for_match_device(const char *pro) { if (run_cmds("CFG:", nullptr)) return -1; Timer usb_timer; while (1) { CAutoList l; if (!l.good()) { break; } size_t i = 0; libusb_device *dev; while ((dev = l.list[i++]) != nullptr) { struct libusb_device_descriptor desc; int r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { set_last_err_string("failure get device descrior"); return -1; } string str = get_device_path(dev); if (!g_filter_usbpath.is_valid(str)) continue; ConfigItem *item = get_config()->find(desc.idVendor, desc.idProduct, desc.bcdDevice); if (item && item->m_protocol == str_to_upper(pro)) { uuu_notify nt; nt.type = uuu_notify::NOFITY_DEV_ATTACH; m_config_item = item; m_current_bcd = desc.bcdDevice; int ret; if (ret = open_libusb(dev, &(m_dev))) return ret; nt.str = (char*)str.c_str(); call_notify(nt); return 0; } } this_thread::sleep_for(200ms); uuu_notify nt; nt.type = nt.NOTIFY_WAIT_FOR; nt.str = (char*)"Wait for Known USB"; call_notify(nt); check_usb_timeout(usb_timer); } return -1; } int uuu_add_usbpath_filter(const char *path) { g_filter_usbpath.push_back(path); return 0; } int uuu_for_each_devices(uuu_ls_usb_devices fn, void *p) { CAutoList l; size_t i = 0; libusb_device *dev; if (!l.good()) { return -1; } while ((dev = l.list[i++]) != nullptr) { struct libusb_device_descriptor desc; int r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { set_last_err_string("failure get device descrior"); return -1; } string str = get_device_path(dev); ConfigItem *item = get_config()->find(desc.idVendor, desc.idProduct, desc.bcdDevice); if (item) { if (fn(str.c_str(), item->m_chip.c_str(), item->m_protocol.c_str(), desc.idVendor, desc.idProduct, desc.bcdDevice, p)) { set_last_err_string("call back return error"); return -1; } } } return 0; } int uuu_set_wait_timeout(int timeout_in_seconds) { g_wait_usb_timeout = seconds{timeout_in_seconds}; return 0; } void uuu_set_poll_period(int period_in_milliseconds) { g_usb_poll_period = milliseconds{period_in_milliseconds}; } int uuu_set_wait_next_timeout(int timeout_in_seconds) { g_wait_next_usb_timeout = seconds{timeout_in_seconds}; return 0; } mfgtools-uuu_1.4.193/libuuu/version.cpp000066400000000000000000000051011417203213400201110ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "gitversion.h" #include "libuuu.h" #include using namespace std; static constexpr auto g_version = GIT_VERSION; const char *uuu_get_version_string() { return g_version; } int uuu_get_version() { string version_str{g_version}; // Find first dot because major version number must be before it auto pos = version_str.find("."); // Find the position of the character right before the start of the number auto vs = version_str.find_last_not_of("0123456789", pos - 1); // Let "vs" point exactly to the first character of the major version number ++vs; string temp_num_str = version_str.substr(vs, pos - vs); const auto maj = static_cast(stoll(temp_num_str, nullptr, 10)); version_str = version_str.substr(pos + 1); pos = version_str.find("."); temp_num_str = version_str.substr(0, pos); const auto min = static_cast(stoll(temp_num_str, nullptr, 10)); version_str = version_str.substr(pos + 1); temp_num_str = version_str.substr(0, pos = version_str.find("-")); const auto build = static_cast(stoll(temp_num_str, nullptr, 10)); return (maj << 24) | (min << 12) | build; } mfgtools-uuu_1.4.193/libuuu/zip.cpp000066400000000000000000000201221417203213400172260ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include "buffer.h" #include "libcomm.h" #include "libuuu.h" #include "liberror.h" #include "zip.h" #define CHUNK 0x10000 int Zip::BuildDirInfo() { shared_ptr zipfile = get_file_buffer(m_filename); if (zipfile == nullptr) { return -1; } size_t i; Zip_eocd *peocd = nullptr; Zip64_eocd_locator *peocd64_loc = nullptr; Zip64_eocd *peocd64 = nullptr; for (i = zipfile->size() - sizeof(Zip_eocd); i > 0; i--) { peocd = (Zip_eocd*)(zipfile->data() + i); if (peocd->sign == EOCD_SIGNATURE) { if (peocd->offset_of_central_dir == 0xFFFFFFFF) {//zip64 for (size_t j = i - sizeof(Zip64_eocd_locator); j > 0; j--) { peocd64_loc = (Zip64_eocd_locator*)(zipfile->data() + j); if (peocd64_loc->sign == EOCD64_LOCATOR_SIGNATURE) { peocd64 = (Zip64_eocd*)(zipfile->data() + peocd64_loc->offset_of_eocd); if (peocd64->sign != EOCD64_SIGNATURE) { set_last_err_string("Can't find EOCD64_SIGNATURE, not a zip64 file"); return -1; } break; } if (zipfile->size() - j > 0x10000) { set_last_err_string("Can't find EOCD, not a zip file"); return -1; } } } break; } if (zipfile->size() - i > 0x10000) { set_last_err_string("Can't find EOCD, not a zip file"); return -1; } } if (peocd == 0) { set_last_err_string("Can't find EOCD, not a zip file"); return -1; } i = peocd64? peocd64->offset:peocd->offset_of_central_dir; size_t total = i; total += peocd64 ? peocd64->size: peocd->size_of_central_dir; while (i < total) { Zip_central_dir *pdir = (Zip_central_dir *)(zipfile->data() + i); if (pdir->sign != DIR_SIGNTURE) { set_last_err_string("DIR signature missmatched"); return -1; } Zip_file_Info info; info.m_filename.append((char*)pdir->filename, pdir->file_name_length); info.m_offset = pdir->offset; info.m_filesize = pdir->uncompressed_size; info.m_timestamp = (pdir->last_modidfy_date << 16) + pdir->last_modidfy_time; info.m_compressedsize = pdir->compressed_size; if (pdir->extrafield_length) { size_t e; for (e = 0; e < pdir->extrafield_length; /*dummy*/) { Zip_ext *ext = (Zip_ext*)(zipfile->data() + e + i + sizeof(Zip_central_dir) + pdir->file_name_length); if (ext->tag == 0x1) { size_t cur64 = 0; if (info.m_filesize == 0xFFFFFFFF) { info.m_filesize = *((uint64_t*)(((uint8_t*)ext) + sizeof(Zip_ext) + cur64)); cur64 += 8; } if (cur64 > ext->size) { set_last_err_string("error pass zip64"); return -1; } if (info.m_compressedsize == 0xFFFFFFFF) { info.m_compressedsize = *((uint64_t*)(((uint8_t*)ext) + sizeof(Zip_ext) + cur64)); cur64 += 8; } if (cur64 > ext->size) { set_last_err_string("error pass zip64"); return -1; } if (info.m_offset == 0xFFFFFFFF) { info.m_offset = *((uint64_t*)(((uint8_t*)ext) + sizeof(Zip_ext) + cur64)); cur64 += 8; } if (cur64 > ext->size) { set_last_err_string("error pass zip64"); return -1; } break; } e += ext->size + sizeof(Zip_ext); } } i += sizeof(Zip_central_dir) + pdir->extrafield_length + pdir->file_name_length + pdir->file_comment_length; m_filemap[info.m_filename] = info; } return 0; } bool Zip::check_file_exist(string filename) { if (m_filemap.find(filename) == m_filemap.end()) { string err; err += "Can't find file "; err += filename; set_last_err_string(err); return false; } return true; } int Zip::get_file_buff(string filename, shared_ptr p) { if (m_filemap.find(filename) == m_filemap.end()) { string err; err += "Can't find file "; err += filename; set_last_err_string(err); return -1; } uuu_notify ut; ut.type = uuu_notify::NOTIFY_DECOMPRESS_START; ut.str = (char*)filename.c_str(); call_notify(ut); return m_filemap[filename].decompress(this, p); } int Zip::Open(string filename) { m_filename = filename; return BuildDirInfo(); } Zip_file_Info::Zip_file_Info() { } Zip_file_Info::~Zip_file_Info() { memset(&m_strm, 0, sizeof(m_strm)); } int Zip_file_Info::decompress(Zip *pZip, shared_ptrp) { p->resize(m_filesize); atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_KNOWN_SIZE); p->m_request_cv.notify_all(); uuu_notify ut; ut.type = uuu_notify::NOTIFY_DECOMPRESS_SIZE; ut.total = m_filesize; call_notify(ut); size_t lastpos = 0; shared_ptr zipfile = get_file_buffer(pZip->get_filename()); if (zipfile == nullptr) return -1; Zip_file_desc *file_desc=(Zip_file_desc *)(zipfile->data() + m_offset); if (file_desc->sign != FILE_SIGNATURE) { set_last_err_string("file signature miss matched"); return -1; } size_t off = sizeof(Zip_file_desc) + file_desc->file_name_length + file_desc->extrafield_length; if (file_desc->compress_method == 0) { p->ref_other_buffer(zipfile, m_offset + off, m_filesize); atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); return 0; } if (file_desc->compress_method != 8) { set_last_err_string("Unsupport compress method"); return -1; } int ret; size_t pos = 0; memset(&m_strm, 0, sizeof(m_strm)); inflateInit2(&m_strm, -MAX_WBITS); /* decompress until deflate stream ends or end of file */ m_strm.avail_in = m_compressedsize; m_strm.next_in = zipfile->data() + m_offset + off; m_strm.total_in = m_compressedsize; /* run inflate() on input until output buffer not full */ size_t each_out_size = CHUNK; do { if (p->size() - pos < each_out_size) each_out_size = p->size() - pos; m_strm.avail_out = each_out_size; m_strm.next_out = p->data() + pos; ret = inflate(&m_strm, Z_NO_FLUSH); //assert(ret != Z_STREAM_ERROR); /* state not clobbered */ switch (ret) { case Z_NEED_DICT: ret = Z_DATA_ERROR; /* and fall through */ case Z_DATA_ERROR: case Z_MEM_ERROR: (void)inflateEnd(&m_strm); return -1; } size_t have = each_out_size - m_strm.avail_out; p->m_avaible_size = pos; p->m_request_cv.notify_all(); pos += have; if (pos - lastpos > 100 * 1024 * 1024) { uuu_notify ut; ut.type = uuu_notify::NOTIFY_DECOMPRESS_POS; ut.index = pos; call_notify(ut); lastpos = pos; } } while (ret != Z_STREAM_END); /* clean up and return */ (void)inflateEnd(&m_strm); if (ret != Z_STREAM_END) { set_last_err_string("decompress error"); return -1; } p->m_avaible_size = m_filesize; atomic_fetch_or(&p->m_dataflags, FILEBUFFER_FLAG_LOADED); p->m_request_cv.notify_all(); ut.type = uuu_notify::NOTIFY_DECOMPRESS_POS; ut.index = m_filesize; call_notify(ut); return 0; } mfgtools-uuu_1.4.193/libuuu/zip.h000066400000000000000000000106731417203213400167050ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include "backfile.h" #include "zlib.h" #include #include #include class FileBuffer; #pragma pack(1) struct Zip_data_desc { uint32_t sign; uint32_t crc; uint32_t compressed_size; uint32_t uncompressed_size; }; struct Zip_file_desc { uint32_t sign; uint16_t version_mini_extract; uint16_t flags; uint16_t compress_method; uint16_t last_modidfy_time; uint16_t last_modidfy_date; uint32_t crc; uint32_t compressed_size; uint32_t uncompressed_size; uint16_t file_name_length; uint16_t extrafield_length; uint8_t filename[0]; }; struct Zip_central_dir { uint32_t sign; uint16_t version; uint16_t version_mini_extract; uint16_t flags; uint16_t compress_method; uint16_t last_modidfy_time; uint16_t last_modidfy_date; uint32_t crc; uint32_t compressed_size; uint32_t uncompressed_size; uint16_t file_name_length; uint16_t extrafield_length; uint16_t file_comment_length; uint16_t disk_number; uint16_t internal_file_attr; uint32_t external_file_attr; uint32_t offset; uint8_t filename[0]; }; struct Zip64_central_dir { uint32_t sign; uint16_t version; uint16_t version_mini_extract; uint16_t flags; uint16_t compress_method; uint16_t last_modidfy_time; uint16_t last_modidfy_date; uint32_t crc; uint32_t compressed_size; uint32_t uncompressed_size; uint16_t file_name_length; uint16_t extrafield_length; uint16_t file_comment_length; uint16_t disk_number; uint16_t internal_file_attr; uint32_t external_file_attr; uint32_t offset; uint8_t filename[0]; }; struct Zip_eocd { uint32_t sign; uint16_t num_of_thisdisk; uint16_t start_disk_of_dir; uint16_t num_of_dir_ondisk; uint16_t num_of_dir; uint32_t size_of_central_dir; uint32_t offset_of_central_dir; uint16_t length_of_comment; uint8_t comment[0]; }; struct Zip64_eocd_locator { uint32_t sign; uint32_t num_of_thisdisk; uint64_t offset_of_eocd; uint32_t total_num_disks; }; struct Zip64_eocd { uint32_t sign; uint64_t size_of_eocd; uint16_t version; uint16_t version_mini_extract; uint32_t num_of_dir_ondisk; uint32_t num_of_disk; uint64_t total_ondisk; uint64_t total; uint64_t size; uint64_t offset; }; struct Zip_ext { uint16_t tag; uint16_t size; }; #define EOCD_SIGNATURE 0x06054b50 #define DIR_SIGNTURE 0x02014b50 #define DATA_SIGNATURE 0x08074b50 #define FILE_SIGNATURE 0x04034b50 #define EOCD64_LOCATOR_SIGNATURE 0x07064b50 #define EOCD64_SIGNATURE 0x06064b50 class Zip; class Zip_file_Info { public: Zip_file_Info(); ~Zip_file_Info(); int decompress(Zip *pZip, std::shared_ptr p); private: std::string m_filename; uint32_t m_timestamp; size_t m_filesize; size_t m_compressedsize; size_t m_offset; z_stream m_strm; bool m_decompressed; friend Zip; }; class Zip : public Backfile { public: int BuildDirInfo(); bool check_file_exist(std::string filename); int get_file_buff(std::string filename, std::shared_ptrp); int Open(std::string filename); std::map m_filemap; }; #pragma pack() mfgtools-uuu_1.4.193/msvc/000077500000000000000000000000001417203213400153665ustar00rootroot00000000000000mfgtools-uuu_1.4.193/msvc/bzip2.vcxproj000066400000000000000000000326401417203213400200360ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing 15.0 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF} Win32Proj bzip2 10.0.16299.0 StaticLibrary true v141 Unicode StaticLibrary false v141 true Unicode StaticLibrary true v141 MultiByte StaticLibrary false v141 true Unicode true true $(SolutionDir)$(Platform)\$(Configuration)\ false $(SolutionDir)$(Platform)\$(Configuration)\ false Use Level3 Disabled false _DEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS; _CRT_NONSTDC_NO_DEPRECATE;;_CRT_SECURE_NO_WARNINGS; _CRT_NONSTDC_NO_DEPRECATE; true Windows true true Use Level3 Disabled false WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) _CRT_SECURE_NO_WARNINGS setmode=_setmode;_CRT_SECURE_NO_WARNINGS; _CRT_NONSTDC_NO_DEPRECATE; true Windows true Use Level3 MaxSpeed true true false WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) _CRT_SECURE_NO_WARNINGS setmode=_setmode;_CRT_SECURE_NO_WARNINGS; _CRT_NONSTDC_NO_DEPRECATE; true MultiThreaded Windows true true true Use Level3 MaxSpeed true true false NDEBUG;_LIB;%(PreprocessorDefinitions) _CRT_SECURE_NO_WARNINGS setmode=_setmode;_CRT_SECURE_NO_WARNINGS; _CRT_NONSTDC_NO_DEPRECATE; true MultiThreaded Windows true true true mfgtools-uuu_1.4.193/msvc/bzip2.vcxproj.filters000066400000000000000000000036131417203213400215030ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files mfgtools-uuu_1.4.193/msvc/createversion.bat000066400000000000000000000005141417203213400207270ustar00rootroot00000000000000@echo off call git --version IF ERRORLEVEL 1 ( echo build from tarball ) ELSE ( IF "%APPVEYOR_BUILD_VERSION%" == "" ( echo build not from appveryor ) ELSE ( git tag uuu_%APPVEYOR_BUILD_VERSION% ) FOR /F "tokens=*" %%a in ('call git describe --tags --long') do ( echo #define GIT_VERSION "lib%%a" > %1/gitversion.h ) )mfgtools-uuu_1.4.193/msvc/libuuu.filters000066400000000000000000000021711417203213400202660ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Header Files Source Files mfgtools-uuu_1.4.193/msvc/libuuu.vcxproj000066400000000000000000000246761417203213400203270ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 15.0 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC} Win32Proj StaticLib1 10.0.16299.0 StaticLibrary true v141 MultiByte StaticLibrary false v141 true MultiByte StaticLibrary true v141 MultiByte StaticLibrary false v141 true MultiByte true $(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2 true $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2 false $(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2 false $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2 NotUsing Level3 Disabled true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true ..\libusb\libusb Windows true createversion.bat ..\libuuu NotUsing Level3 Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) true ..\libusb\libusb Windows true createversion.bat ..\libuuu NotUsing Level3 MaxSpeed true true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true ..\libusb\libusb MultiThreaded Windows true true true createversion.bat ..\libuuu NotUsing Level3 MaxSpeed true true true NDEBUG;_LIB;%(PreprocessorDefinitions) true ..\libusb\libusb MultiThreaded Windows true true true createversion.bat ..\libuuu mfgtools-uuu_1.4.193/msvc/libuuu.vcxproj.filters000066400000000000000000000077171417203213400217730ustar00rootroot00000000000000 {56b8d729-e8e8-4b90-be62-ef7a1d4e77c2} {9880b066-0013-4325-97c5-de85ce13b31f} Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files mfgtools-uuu_1.4.193/msvc/uuu-static-link.sln000066400000000000000000000112441417203213400211440ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27130.2027 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuuu", "libuuu.vcxproj", "{048A9BD1-EEF8-4119-9DEF-219D7E177AAC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib.vcxproj", "{59666402-A775-49AC-A9BD-19FD528F5FD9}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "bzip2.vcxproj", "{B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "..\libusb\msvc\libusb_static_2017.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uuu-static-link", "uuu-static-link.vcxproj", "{2950F8EE-7895-4431-858A-C21EE105C242}" ProjectSection(ProjectDependencies) = postProject {59666402-A775-49AC-A9BD-19FD528F5FD9} = {59666402-A775-49AC-A9BD-19FD528F5FD9} {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF} = {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF} {048A9BD1-EEF8-4119-9DEF-219D7E177AAC} = {048A9BD1-EEF8-4119-9DEF-219D7E177AAC} {349EE8F9-7D25-4909-AAF5-FF3FADE72187} = {349EE8F9-7D25-4909-AAF5-FF3FADE72187} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Debug|x64.ActiveCfg = Debug|x64 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Debug|x64.Build.0 = Debug|x64 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Debug|x86.ActiveCfg = Debug|Win32 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Debug|x86.Build.0 = Debug|Win32 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Release|x64.ActiveCfg = Release|x64 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Release|x64.Build.0 = Release|x64 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Release|x86.ActiveCfg = Release|Win32 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Release|x86.Build.0 = Release|Win32 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Debug|x64.ActiveCfg = Debug|x64 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Debug|x64.Build.0 = Debug|x64 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Debug|x86.ActiveCfg = Debug|Win32 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Debug|x86.Build.0 = Debug|Win32 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Release|x64.ActiveCfg = Release|x64 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Release|x64.Build.0 = Release|x64 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Release|x86.ActiveCfg = Release|Win32 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Release|x86.Build.0 = Release|Win32 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Debug|x64.ActiveCfg = Debug|x64 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Debug|x64.Build.0 = Debug|x64 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Debug|x86.ActiveCfg = Debug|Win32 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Debug|x86.Build.0 = Debug|Win32 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Release|x64.ActiveCfg = Release|x64 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Release|x64.Build.0 = Release|x64 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Release|x86.ActiveCfg = Release|Win32 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Release|x86.Build.0 = Release|Win32 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x86.ActiveCfg = Debug|Win32 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x86.Build.0 = Debug|Win32 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x86.ActiveCfg = Release|Win32 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x86.Build.0 = Release|Win32 {2950F8EE-7895-4431-858A-C21EE105C242}.Debug|x64.ActiveCfg = Debug|x64 {2950F8EE-7895-4431-858A-C21EE105C242}.Debug|x64.Build.0 = Debug|x64 {2950F8EE-7895-4431-858A-C21EE105C242}.Debug|x86.ActiveCfg = Debug|Win32 {2950F8EE-7895-4431-858A-C21EE105C242}.Debug|x86.Build.0 = Debug|Win32 {2950F8EE-7895-4431-858A-C21EE105C242}.Release|x64.ActiveCfg = Release|x64 {2950F8EE-7895-4431-858A-C21EE105C242}.Release|x64.Build.0 = Release|x64 {2950F8EE-7895-4431-858A-C21EE105C242}.Release|x86.ActiveCfg = Release|Win32 {2950F8EE-7895-4431-858A-C21EE105C242}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {93EA02D1-E396-4390-B160-58909BBB9556} EndGlobalSection EndGlobal mfgtools-uuu_1.4.193/msvc/uuu-static-link.vcxproj000066400000000000000000000426331417203213400220510ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 15.0 {2950F8EE-7895-4431-858A-C21EE105C242} Win32Proj uuu 10.0.16299.0 Application true v141 MultiByte Application false v141 true MultiByte Application true v141 MultiByte Application false v141 true MultiByte true $(Configuration)\$(ProjectName)\ $(Platform)\$(Configuration) Build uuu true Build $(Platform)\$(Configuration) uuu false $(Configuration)\$(ProjectName)\ $(Platform)\$(Configuration) Build uuu false Build $(Platform)\$(Configuration) uuu NotUsing Level3 Disabled true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true ../libusb/$(Platform)/$(Configuration)/lib/libusb-1.0.lib;$(Platform)/$(Configuration)/libuuu.lib;$(Platform)/$(Configuration)/zlib.lib;%(AdditionalDependencies);$(Platform)/$(Configuration)/bzip2.lib echo R^"####( > $(SolutionDir)\..\uuu\uuu.clst type $(SolutionDir)\..\uuu\uuu.lst >> $(SolutionDir)\..\uuu\uuu.clst echo )####^" >> $(SolutionDir)\..\uuu\uuu.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_loader.clst type $(SolutionDir)\..\uuu\emmc_burn_loader.lst >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\qspi_burn_loader.clst type $(SolutionDir)\..\uuu\qspi_burn_loader.lst >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_loader.clst type $(SolutionDir)\..\uuu\sd_burn_loader.lst >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\spl_boot.clst type $(SolutionDir)\..\uuu\spl_boot.lst >> $(SolutionDir)\..\uuu\spl_boot.clst echo )####^" >> $(SolutionDir)\..\uuu\spl_boot.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_all.clst type $(SolutionDir)\..\uuu\emmc_burn_all.lst >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_all.clst type $(SolutionDir)\..\uuu\sd_burn_all.lst >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\fat_write.clst type $(SolutionDir)\..\uuu\fat_write.lst >> $(SolutionDir)\..\uuu\fat_write.clst echo )####^" >> $(SolutionDir)\..\uuu\fat_write.clst echo R^"####( > $(SolutionDir)\..\uuu\nand_burn_loader.clst type $(SolutionDir)\..\uuu\nand_burn_loader.lst >> $(SolutionDir)\..\uuu\nand_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\nand_burn_loader.clst true NotUsing Level3 Disabled true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true ../libusb/$(Platform)/$(Configuration)/lib/libusb-1.0.lib;$(Platform)/$(Configuration)/libuuu.lib;$(Platform)/$(Configuration)/zlib.lib;%(AdditionalDependencies);$(Platform)/$(Configuration)/bzip2.lib echo R^"####( > $(SolutionDir)\..\uuu\uuu.clst type $(SolutionDir)\..\uuu\uuu.lst >> $(SolutionDir)\..\uuu\uuu.clst echo )####^" >> $(SolutionDir)\..\uuu\uuu.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_loader.clst type $(SolutionDir)\..\uuu\emmc_burn_loader.lst >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\qspi_burn_loader.clst type $(SolutionDir)\..\uuu\qspi_burn_loader.lst >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_loader.clst type $(SolutionDir)\..\uuu\sd_burn_loader.lst >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\spl_boot.clst type $(SolutionDir)\..\uuu\spl_boot.lst >> $(SolutionDir)\..\uuu\spl_boot.clst echo )####^" >> $(SolutionDir)\..\uuu\spl_boot.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_all.clst type $(SolutionDir)\..\uuu\emmc_burn_all.lst >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_all.clst type $(SolutionDir)\..\uuu\sd_burn_all.lst >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\fat_write.clst type $(SolutionDir)\..\uuu\fat_write.lst >> $(SolutionDir)\..\uuu\fat_write.clst echo )####^" >> $(SolutionDir)\..\uuu\fat_write.clst echo R^"####( > $(SolutionDir)\..\uuu\nand_burn_loader.clst type $(SolutionDir)\..\uuu\nand_burn_loader.lst >> $(SolutionDir)\..\uuu\nand_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\nand_burn_loader.clst true NotUsing Level3 MaxSpeed true true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded Console true true true ../libusb/$(Platform)/$(Configuration)/lib/libusb-1.0.lib;$(Platform)/$(Configuration)/libuuu.lib;$(Platform)/$(Configuration)/zlib.lib;%(AdditionalDependencies);$(Platform)/$(Configuration)/bzip2.lib echo R^"####( > $(SolutionDir)\..\uuu\uuu.clst type $(SolutionDir)\..\uuu\uuu.lst >> $(SolutionDir)\..\uuu\uuu.clst echo )####^" >> $(SolutionDir)\..\uuu\uuu.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_loader.clst type $(SolutionDir)\..\uuu\emmc_burn_loader.lst >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\qspi_burn_loader.clst type $(SolutionDir)\..\uuu\qspi_burn_loader.lst >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_loader.clst type $(SolutionDir)\..\uuu\sd_burn_loader.lst >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\spl_boot.clst type $(SolutionDir)\..\uuu\spl_boot.lst >> $(SolutionDir)\..\uuu\spl_boot.clst echo )####^" >> $(SolutionDir)\..\uuu\spl_boot.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_all.clst type $(SolutionDir)\..\uuu\emmc_burn_all.lst >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_all.clst type $(SolutionDir)\..\uuu\sd_burn_all.lst >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\fat_write.clst type $(SolutionDir)\..\uuu\fat_write.lst >> $(SolutionDir)\..\uuu\fat_write.clst echo )####^" >> $(SolutionDir)\..\uuu\fat_write.clst echo R^"####( > $(SolutionDir)\..\uuu\nand_burn_loader.clst type $(SolutionDir)\..\uuu\nand_burn_loader.lst >> $(SolutionDir)\..\uuu\nand_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\nand_burn_loader.clst true NotUsing Level3 MaxSpeed true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded Console true true true ../libusb/$(Platform)/$(Configuration)/lib/libusb-1.0.lib;$(Platform)/$(Configuration)/libuuu.lib;$(Platform)/$(Configuration)/zlib.lib;%(AdditionalDependencies);$(Platform)/$(Configuration)/bzip2.lib echo R^"####( > $(SolutionDir)\..\uuu\uuu.clst type $(SolutionDir)\..\uuu\uuu.lst >> $(SolutionDir)\..\uuu\uuu.clst echo )####^" >> $(SolutionDir)\..\uuu\uuu.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_loader.clst type $(SolutionDir)\..\uuu\emmc_burn_loader.lst >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\qspi_burn_loader.clst type $(SolutionDir)\..\uuu\qspi_burn_loader.lst >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_loader.clst type $(SolutionDir)\..\uuu\sd_burn_loader.lst >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\spl_boot.clst type $(SolutionDir)\..\uuu\spl_boot.lst >> $(SolutionDir)\..\uuu\spl_boot.clst echo )####^" >> $(SolutionDir)\..\uuu\spl_boot.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_all.clst type $(SolutionDir)\..\uuu\emmc_burn_all.lst >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_all.clst type $(SolutionDir)\..\uuu\sd_burn_all.lst >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\fat_write.clst type $(SolutionDir)\..\uuu\fat_write.lst >> $(SolutionDir)\..\uuu\fat_write.clst echo )####^" >> $(SolutionDir)\..\uuu\fat_write.clst echo R^"####( > $(SolutionDir)\..\uuu\nand_burn_loader.clst type $(SolutionDir)\..\uuu\nand_burn_loader.lst >> $(SolutionDir)\..\uuu\nand_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\nand_burn_loader.clst true mfgtools-uuu_1.4.193/msvc/uuu.sln000066400000000000000000000112061417203213400167220ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27130.2027 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uuu", "uuu.vcxproj", "{2950F8EE-7895-4431-858A-C21EE105C242}" ProjectSection(ProjectDependencies) = postProject {59666402-A775-49AC-A9BD-19FD528F5FD9} = {59666402-A775-49AC-A9BD-19FD528F5FD9} {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF} = {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF} {048A9BD1-EEF8-4119-9DEF-219D7E177AAC} = {048A9BD1-EEF8-4119-9DEF-219D7E177AAC} {349EE8FA-7D25-4909-AAF5-FF3FADE72187} = {349EE8FA-7D25-4909-AAF5-FF3FADE72187} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuuu", "libuuu.vcxproj", "{048A9BD1-EEF8-4119-9DEF-219D7E177AAC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib.vcxproj", "{59666402-A775-49AC-A9BD-19FD528F5FD9}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (dll)", "..\libusb\msvc\libusb_dll_2017.vcxproj", "{349EE8FA-7D25-4909-AAF5-FF3FADE72187}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "bzip2.vcxproj", "{B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2950F8EE-7895-4431-858A-C21EE105C242}.Debug|x64.ActiveCfg = Debug|x64 {2950F8EE-7895-4431-858A-C21EE105C242}.Debug|x64.Build.0 = Debug|x64 {2950F8EE-7895-4431-858A-C21EE105C242}.Debug|x86.ActiveCfg = Debug|Win32 {2950F8EE-7895-4431-858A-C21EE105C242}.Debug|x86.Build.0 = Debug|Win32 {2950F8EE-7895-4431-858A-C21EE105C242}.Release|x64.ActiveCfg = Release|x64 {2950F8EE-7895-4431-858A-C21EE105C242}.Release|x64.Build.0 = Release|x64 {2950F8EE-7895-4431-858A-C21EE105C242}.Release|x86.ActiveCfg = Release|Win32 {2950F8EE-7895-4431-858A-C21EE105C242}.Release|x86.Build.0 = Release|Win32 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Debug|x64.ActiveCfg = Debug|x64 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Debug|x64.Build.0 = Debug|x64 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Debug|x86.ActiveCfg = Debug|Win32 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Debug|x86.Build.0 = Debug|Win32 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Release|x64.ActiveCfg = Release|x64 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Release|x64.Build.0 = Release|x64 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Release|x86.ActiveCfg = Release|Win32 {048A9BD1-EEF8-4119-9DEF-219D7E177AAC}.Release|x86.Build.0 = Release|Win32 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Debug|x64.ActiveCfg = Debug|x64 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Debug|x64.Build.0 = Debug|x64 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Debug|x86.ActiveCfg = Debug|Win32 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Debug|x86.Build.0 = Debug|Win32 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Release|x64.ActiveCfg = Release|x64 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Release|x64.Build.0 = Release|x64 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Release|x86.ActiveCfg = Release|Win32 {59666402-A775-49AC-A9BD-19FD528F5FD9}.Release|x86.Build.0 = Release|Win32 {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64 {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64 {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|x86.ActiveCfg = Debug|Win32 {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|x86.Build.0 = Debug|Win32 {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64 {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64 {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|x86.ActiveCfg = Release|Win32 {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|x86.Build.0 = Release|Win32 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Debug|x64.ActiveCfg = Debug|x64 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Debug|x64.Build.0 = Debug|x64 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Debug|x86.ActiveCfg = Debug|Win32 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Debug|x86.Build.0 = Debug|Win32 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Release|x64.ActiveCfg = Release|x64 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Release|x64.Build.0 = Release|x64 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Release|x86.ActiveCfg = Release|Win32 {B54C35CD-5FFE-4FEA-90BA-32894BCFC6BF}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {93EA02D1-E396-4390-B160-58909BBB9556} EndGlobalSection EndGlobal mfgtools-uuu_1.4.193/msvc/uuu.vcxproj000066400000000000000000000436771417203213400176420ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 15.0 {2950F8EE-7895-4431-858A-C21EE105C242} Win32Proj uuu 10.0.16299.0 Application true v141 MultiByte Application false v141 true MultiByte Application true v141 MultiByte Application false v141 true MultiByte true $(Configuration)\$(ProjectName)\ $(Platform)\$(Configuration) Build true Build $(Platform)\$(Configuration) false $(Configuration)\$(ProjectName)\ $(Platform)\$(Configuration) Build false Build $(Platform)\$(Configuration) NotUsing Level3 Disabled true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true ../libusb/$(Platform)/$(Configuration)/dll/libusb-1.0.lib;$(Platform)/$(Configuration)/libuuu.lib;$(Platform)/$(Configuration)/zlib.lib;%(AdditionalDependencies);$(Platform)/$(Configuration)/bzip2.lib echo R^"####( > $(SolutionDir)\..\uuu\uuu.clst type $(SolutionDir)\..\uuu\uuu.lst >> $(SolutionDir)\..\uuu\uuu.clst echo )####^" >> $(SolutionDir)\..\uuu\uuu.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_loader.clst type $(SolutionDir)\..\uuu\emmc_burn_loader.lst >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\qspi_burn_loader.clst type $(SolutionDir)\..\uuu\qspi_burn_loader.lst >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_loader.clst type $(SolutionDir)\..\uuu\sd_burn_loader.lst >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\spl_boot.clst type $(SolutionDir)\..\uuu\spl_boot.lst >> $(SolutionDir)\..\uuu\spl_boot.clst echo )####^" >> $(SolutionDir)\..\uuu\spl_boot.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_all.clst type $(SolutionDir)\..\uuu\emmc_burn_all.lst >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_all.clst type $(SolutionDir)\..\uuu\sd_burn_all.lst >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\fat_write.clst type $(SolutionDir)\..\uuu\fat_write.lst >> $(SolutionDir)\..\uuu\fat_write.clst echo )####^" >> $(SolutionDir)\..\uuu\fat_write.clst echo R^"####( > $(SolutionDir)\..\uuu\nand_burn_loader.clst type $(SolutionDir)\..\uuu\nand_burn_loader.lst >> $(SolutionDir)\..\uuu\nand_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\nand_burn_loader.clst true copy /y "$(SolutionDir)..\libusb\$(Platform)\$(Configuration)\dll\*.dll" $(Platform)\$(Configuration)\ NotUsing Level3 Disabled true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true ../libusb/$(Platform)/$(Configuration)/dll/libusb-1.0.lib;$(Platform)/$(Configuration)/libuuu.lib;$(Platform)/$(Configuration)/zlib.lib;%(AdditionalDependencies);$(Platform)/$(Configuration)/bzip2.lib echo R^"####( > $(SolutionDir)\..\uuu\uuu.clst type $(SolutionDir)\..\uuu\uuu.lst >> $(SolutionDir)\..\uuu\uuu.clst echo )####^" >> $(SolutionDir)\..\uuu\uuu.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_loader.clst type $(SolutionDir)\..\uuu\emmc_burn_loader.lst >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\qspi_burn_loader.clst type $(SolutionDir)\..\uuu\qspi_burn_loader.lst >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_loader.clst type $(SolutionDir)\..\uuu\sd_burn_loader.lst >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\spl_boot.clst type $(SolutionDir)\..\uuu\spl_boot.lst >> $(SolutionDir)\..\uuu\spl_boot.clst echo )####^" >> $(SolutionDir)\..\uuu\spl_boot.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_all.clst type $(SolutionDir)\..\uuu\emmc_burn_all.lst >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_all.clst type $(SolutionDir)\..\uuu\sd_burn_all.lst >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\fat_write.clst type $(SolutionDir)\..\uuu\fat_write.lst >> $(SolutionDir)\..\uuu\fat_write.clst echo )####^" >> $(SolutionDir)\..\uuu\fat_write.clst echo R^"####( > $(SolutionDir)\..\uuu\nand_burn_loader.clst type $(SolutionDir)\..\uuu\nand_burn_loader.lst >> $(SolutionDir)\..\uuu\nand_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\nand_burn_loader.clst true copy /y "$(SolutionDir)..\libusb\$(Platform)\$(Configuration)\dll\*.dll" $(Platform)\$(Configuration)\ NotUsing Level3 MaxSpeed true true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded Console true true true ../libusb/$(Platform)/$(Configuration)/dll/libusb-1.0.lib;$(Platform)/$(Configuration)/libuuu.lib;$(Platform)/$(Configuration)/zlib.lib;%(AdditionalDependencies);$(Platform)/$(Configuration)/bzip2.lib echo R^"####( > $(SolutionDir)\..\uuu\uuu.clst type $(SolutionDir)\..\uuu\uuu.lst >> $(SolutionDir)\..\uuu\uuu.clst echo )####^" >> $(SolutionDir)\..\uuu\uuu.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_loader.clst type $(SolutionDir)\..\uuu\emmc_burn_loader.lst >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\qspi_burn_loader.clst type $(SolutionDir)\..\uuu\qspi_burn_loader.lst >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_loader.clst type $(SolutionDir)\..\uuu\sd_burn_loader.lst >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\spl_boot.clst type $(SolutionDir)\..\uuu\spl_boot.lst >> $(SolutionDir)\..\uuu\spl_boot.clst echo )####^" >> $(SolutionDir)\..\uuu\spl_boot.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_all.clst type $(SolutionDir)\..\uuu\emmc_burn_all.lst >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_all.clst type $(SolutionDir)\..\uuu\sd_burn_all.lst >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\fat_write.clst type $(SolutionDir)\..\uuu\fat_write.lst >> $(SolutionDir)\..\uuu\fat_write.clst echo )####^" >> $(SolutionDir)\..\uuu\fat_write.clst echo R^"####( > $(SolutionDir)\..\uuu\nand_burn_loader.clst type $(SolutionDir)\..\uuu\nand_burn_loader.lst >> $(SolutionDir)\..\uuu\nand_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\nand_burn_loader.clst true copy /y "$(SolutionDir)..\libusb\$(Platform)\$(Configuration)\dll\*.dll" $(Platform)\$(Configuration)\ NotUsing Level3 MaxSpeed true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded Console true true true ../libusb/$(Platform)/$(Configuration)/dll/libusb-1.0.lib;$(Platform)/$(Configuration)/libuuu.lib;$(Platform)/$(Configuration)/zlib.lib;%(AdditionalDependencies);$(Platform)/$(Configuration)/bzip2.lib echo R^"####( > $(SolutionDir)\..\uuu\uuu.clst type $(SolutionDir)\..\uuu\uuu.lst >> $(SolutionDir)\..\uuu\uuu.clst echo )####^" >> $(SolutionDir)\..\uuu\uuu.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_loader.clst type $(SolutionDir)\..\uuu\emmc_burn_loader.lst >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\qspi_burn_loader.clst type $(SolutionDir)\..\uuu\qspi_burn_loader.lst >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\qspi_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_loader.clst type $(SolutionDir)\..\uuu\sd_burn_loader.lst >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_loader.clst echo R^"####( > $(SolutionDir)\..\uuu\spl_boot.clst type $(SolutionDir)\..\uuu\spl_boot.lst >> $(SolutionDir)\..\uuu\spl_boot.clst echo )####^" >> $(SolutionDir)\..\uuu\spl_boot.clst echo R^"####( > $(SolutionDir)\..\uuu\emmc_burn_all.clst type $(SolutionDir)\..\uuu\emmc_burn_all.lst >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\emmc_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\sd_burn_all.clst type $(SolutionDir)\..\uuu\sd_burn_all.lst >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo )####^" >> $(SolutionDir)\..\uuu\sd_burn_all.clst echo R^"####( > $(SolutionDir)\..\uuu\fat_write.clst type $(SolutionDir)\..\uuu\fat_write.lst >> $(SolutionDir)\..\uuu\fat_write.clst echo )####^" >> $(SolutionDir)\..\uuu\fat_write.clst echo R^"####( > $(SolutionDir)\..\uuu\nand_burn_loader.clst type $(SolutionDir)\..\uuu\nand_burn_loader.lst >> $(SolutionDir)\..\uuu\nand_burn_loader.clst echo )####^" >> $(SolutionDir)\..\uuu\nand_burn_loader.clst true copy /y "$(SolutionDir)..\libusb\$(Platform)\$(Configuration)\dll\*.dll" $(Platform)\$(Configuration)\ mfgtools-uuu_1.4.193/msvc/uuu.vcxproj.filters000066400000000000000000000023711417203213400212730ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Source Files Source Files Header Files mfgtools-uuu_1.4.193/msvc/zlib.vcxproj000066400000000000000000000214711417203213400177500ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 15.0 {59666402-A775-49AC-A9BD-19FD528F5FD9} Win32Proj zlib 10.0.16299.0 StaticLibrary true v141 MultiByte StaticLibrary false v141 true MultiByte StaticLibrary true v141 MultiByte StaticLibrary false v141 true MultiByte true true $(SolutionDir)$(Platform)\$(Configuration)\ false $(SolutionDir)$(Platform)\$(Configuration)\ false NotUsing Level3 Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) true false Windows true true NotUsing Level3 Disabled true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true false Windows true true NotUsing Level3 MaxSpeed true true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true false MultiThreaded Windows true true true true NotUsing Level3 MaxSpeed true true true NDEBUG;_LIB;%(PreprocessorDefinitions) true false MultiThreaded Windows true true true true mfgtools-uuu_1.4.193/msvc/zlib.vcxproj.filters000066400000000000000000000047071417203213400214220ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Header Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files mfgtools-uuu_1.4.193/snap/000077500000000000000000000000001417203213400153575ustar00rootroot00000000000000mfgtools-uuu_1.4.193/snap/gui/000077500000000000000000000000001417203213400161435ustar00rootroot00000000000000mfgtools-uuu_1.4.193/snap/gui/universal-update-utility.png000066400000000000000000000146141417203213400236500ustar00rootroot00000000000000‰PNG  IHDR¡É¿ë­sRGB®ÎégAMA± üa pHYs%%IR$ð!IDATx^íÝË‘ÛH€áõAÌ‘§9+ÆEŸÇEÐÞåÐeLicf3 Þ•xCJÿ±l Q••ÕhŠó¿ÿÖåzÿ'vû;Þܯ:®Çù¸…RMî×KØÀ¯OÿÙýƒ¿œÀþeÿ/ôÉw;¼Þ¸æô~«oPèc[æë)çêÙï¹ËÇ-áýÎwg$Þäú3Ÿ¦îLµëªÇñ÷²müª.—ë]jpRúS5ö\0’™ˆÄ‰yb6ˆ®s÷§Lßår½i±'·Z•j1;αþ5\&}íä~ãú¾ž„Q5Ósrš¡y¾Ì®»gýZó Ðrí×cê“Öö´±ó°-6ݵ0š Ç| Ú9«>ZƒQ¶^:ªûµzý…r/b|†®Þi\§;ô^vü‚t™#ë›YU”¾]:dí´ëš&åÍ“(óÄxÉ"pÉSyøoòºè´r‡Ÿk:1›ÆiÑêJÏãhç´ÞUÂßÑT½´²õ¹‘ÈGŸSïg÷ÛU=¶Î;ÛyÒ4»Ç~n>‡æËœ–4t0•ÙñAáu0™N¸ö¾³ÒŸ.Bç]c5¯QSž˜Ë2¼6ç¥]#iÞëÏmWý˜-“´%Vmÿ}i¥ÊRÕë÷Ø3êM:Õ[çí SLøš§(šLö†ÆÓmë!ú‘—°QT~yšk4µ£iMñùY¨k±B »æï9Tÿ"BlTy_«z©œFuަ=~õWÇuÀÂâùRÃq%•äÏ…Ãhì™OrÆŒæ¢3_ÃvùDm¬-,gfž¹î(Š»I#¥<ûð¾‰\—ó [2´lÚï®Ðˆ£ Økù)»&µÈ+6ÈÃs~¬7§ó>Iqê'¼kæ­íù«Î²[úN•~ì ´N—DÚ%T½qm¬áðzø²´ú÷ë£æƒ£á§õ‰Š8YÛ\6³Ýœþ!ÒÆtâIŽñ¸›f5jÈSUYPî«‚}|6L] ç‰Ú—MÃwÁ0fN¯yŽ™Ðy®7.»:ÔŠ8º¶(OÌVå<”SsVÌFúþ« ¯ÞnþFПU˜4½¶g¦“ªì)¦!‹¶<¥Ÿ9ªÝ—%)§”ܦ´ôÐÛÒº5­í¦[Iv¦^Dx)ºÃ:6ž:kŒ®Lã÷†®X’’I½Yçí- %uõ+í¾d%tÍE—gìf”ÏÊ3ÇcFùèÑe@ý(«¥op=£„³ «]ä*½ZŽí÷އ6¡z×ɶvö¦Æçü6­é5CiXCôªÕ0ú?ÎÙIÛǘ.@ÉI0§¶ì¼®êŽq §t×ÃWÕ{dT=ÙÃð§¥OZŸòè²Á³b69x¸ŠNqy™Ž{§ì]S剩¹TrÜS…ôrhë[}ŸdÍH–²%¼;íýXþ¦9Œ mα‰k(ºª4¡•\[\1;”É—ã9+f+Y¥z»Rž¢\iX'Ÿ^ªyÃÖr\?Ö¶3cIµg,kYYïáuC'÷Þ¸†ê§åИʀdó²1~½h—ptŸ«§l[»]ê U:ïç«7™:3ÎG"²jh‹µƒ4r˜ÎX/aK7¼^U°lœµn(Tí)ªG­4º­’ˆlÞ]5 aå m&1EÝ¢D£—ÛĽ­²­eã­äEs—î¨t&›ã:_ÙáÅÀ_V§,‹~}Ê]å\d!eƒgÅlrðð©e¤õór³ÊÙTðÄTÕrÜ^…j+ÅEkjø&Û—å°.Ó#Ç11>Ç&[†b Óø—WUm5Ûê‰Ù¥L¾ÏY1ÛÈણ«·›—¢,M'Ÿnªz’E;ó†[‡Ö¶ç+úÃþ’ýNÓÔÉýÐxê¬1µÉöp+ªý‚«Æ¥ptŸk wsÃTe¿¶¦Ÿì”Þa–IEêI$‡Tïä~p *G[áµÐ*)Éæecüz‘çW·‚¶ûÀxcã±›A>Ï\ñæ#qr&k[ípq®§—p­¤#ü•n*›¨õ$Û¢³·ò—9¦’ж7¿ê€Eœp“×m”³K£Â²9J®Ì´•¼hîÒ£Ön$ùz:eYôëSîÊ_]6xVÌ&Ãçñ9//)÷¶£qgÄtH–éwœ©µCdÛøLò¦Ï¢1Sí- -";ŠZV[µÍk»ž˜]Òìí/ÆÅÈÏŠÙJš¬·`%\>Õ<}È9«NY°4ÃDgW`…¾Õ'AvNÿÚ{Ý5}AQö¹ëæ,N4 y·ÆO3¥•¤6îåë5ѪÜÌ}<®>ë¯Wgë@¿ô+jñï£%H6,S3÷¸)ÿ¸4r­kŒ{sÏÅÈpìf˜ÏB#Gsq<Æê$´›Òs¯:’ú Oóò^]¡uß;>eEn–NzªèÔ˶ðS8ftÎoÓ*Qœpc;ÂkOÎ>Ú…´»4¾f-i¨Ì´•¼hZ6ýëá+ë”eÑ­]"»ÿæ==|¾j¦ ž³Is\3Ù?ñ¼i:ï|g;VÎòwé„'¦OßssötŒ-—¾—§‡Õ«´î‘ÍS¤½OËäû1sÛG¿Wáòam,oS9¤Û¼ËepmñÄìãø>¶Ób¶±Œz³Y ›^ gÓás.jÎ'ŽJÕº´ÞØ‹NlÔ…ÍyØ%âîcIG$'¤žåa·:ao0Íz0½–2‡mãéÕyÎYú\GŸÜ·fÙ¨$`Î2ää×,®´Eæ½õçbƒþØg½||æáašï?¼:ºb¹¹Òw3[Ã95|x¯üâ¦;1‹ÜÅûï] Ö°2¯LlçüqÔðá½òËãÒ ãý÷žtÞ:¿:òžëàœ?Žö>òÿ]Ex#¾>YYdXhlÂ95:’«ôþö EŸ¸ñ{ €wtù¸Ýÿ™Üoaãïãã&oŒûr+#Þ©6¿ùœð¸|\ïËBå~¿^eÙÂ]%‹¡ûõ2½–%ÝúÃK²iÓ®yí­qºØ}Ÿ³æ½æl¦K“ûíc¹Ã‡Ç[¬qg²À»_Ãkc^|ETÏñ¡«ÐwZã¾åœ€-*+“÷z"÷`²úÉkQ¬^kÜž÷œS°Å`e"÷~³ÄèR&Û´ÐgÀчn×r©5޹\—JŠøsD+[ ûfž˜¡kùgì7XÍEkÜÆêMæA&b­Ïíz)ê¼Îµ¸^ïù3ÇMi¯'IV|×¹1ôžs ¶°5‡.Ê%΢¼ÿW–ºJ¹_‹=$«‰qŒEh6ágý¬p±¾ššYžšIWrž‡K¾o°’ÑÏiÛK{•’ ÆU+óÊ3âNL¹§l¹Ê2VVÜÓI¢³x›Ó´)o:§`£ËúØLÑ4p¬Q¢EU$Ý:Ž©¯4lk|œ.v²0k%¼6ž‡8»Ù¬‡tô+ߨ;£òŒ¸Sîi[Ú•sDÕ±­Õø¶7S°ßÅÖ»ù:c¼Fñ,1­…F¹=ýBülxå‰ùuŸã:£òŒ¸Sîi×VŸ³VóŽÔ2<Çà7%‹€ä†?\£\-$¤¥¹öQö º <1•¬ß`=4^ã^ô7€¨ÜöÙÜÖ¨Îo¹§nËMWn»÷§Üx“õÆ|×ñBX#Et9)‹»‹6w`Äžv<1z–ß%$ü8 ͼ¬²Úë$íÛ£ùL?õ»êØUÃ-±‘³ækqV;À?~~ûüüëÇ÷/_|ë¬qeñúù#¬J%òóóϯÓ‘aÌÏ¿CÀ×?~þûíGÙðDǯ½ñ3¹Ë]¯I‹òCAoa÷$Zo¯¤©å<ë÷uš§ß¤O}º£¬”÷Á*e}v¡7;ûT8«=O;›úêëÛóöÑ?GÛ1•mý¦†6ŒËÒ:rš?s¾€Gë­q¿ÿõïçŸáµùþs^­.Æ1²®]îJw?Oƒç8xíÕÃï·u±¦-Ú--¼6vÔà^xѦ¤éð£põuЧßÞô·:eÒ7/‘këgz«Ãk¤ÜY§–§M}5ƒm¶åä죞˜˜Å…×Û¹Ç5§u€»¯³ÚŽè¬qeµš¯Gk+Úa ÏqñR^{+G—-Öîhåݰr”¦¢M®¾Nñô’wmp’ãã»è‡9u¡ëþh¥öYŽñÙ…Þ¦žó!ÃÒk€ý•¢ß¯g =1ûu±ÞãR‚Î9ꉉIØ‘i÷ŽËºgÓå¯aßYíGtÖ¸?>‹õè×??£‡²ÂÃçqñR^{]GÛ/¼^XÇñ ¨rL“ógªÇ9Ö Ms¿¶›è#å²±ü³µG›ý˜iaoêîvža¡ëy ÛXoX¡Ãy¥«æ°+Ö¬á2Ó·0U–ÍÜ^ògqYçS ¯ç¬[§ã5UûkÃúc´¿^Óô”®Xf¨ Û㘹|ÍÞ¬Sò²䉉i§ã¨ÏØOèÆøú«·£[;,}bšˆqĤÚkÜ/•g®ùúÕ“úúåû?~ê¿Q €ß±†Ä4½dLJ8p ·u±Ð{žgw¾ðzuÉûcºÉÕ—YªP°‡ötWËsÊ‹-Òætu“,“l½“ö艮µÁyNzbZ Ö‹VÐÚ§™ZvéZ¶Xk(Õbçˆ6¨Mèöµ-ýÉΞðsµ¯H3gc3&çÄò™ ël‰–cë-KFÐéÚ ÛžcsX™Â¤6â2'OLĆçJªÍ5®t>vs×pà¬v€#ÚkÜÚç òõ«'Fè8üœ¿{áó§ý[·° x¶ã×Þ郳v_ÖEDåY¦ÝùÂëHÖsvÔf‹»á¸/c7Rèßo›¦ã‹²$Ö•–Óc²±?ÚñIÏØ"©½Ðµ™¬î’D²ç¹9jW¯Ü1½¬Ù¶nÍÙèîΜU{Sõ<¶ó´³©/ Î m%XŽ«¼òÄ,´Fï—¦‰Û¦vœÕpÄßãêúb?üñ•…-^À©×Þ‹­A‹{¿ÝùÂëHÖ³Þ-c£Gƒõ¾N¡E©µÝÂ[w󸞞˜I+ÒOÛl(§÷ÔI_4§£QMU&’å¶µÎÉá¶czYv4élïÎÈ`ÆZÍžVzO;ûʆ¤GÇ?×F쉙YìCwŒKò8¥Ê›kØToG·vX-‰i"Æ“ê~·ø÷dÅ3ZOÌâë÷¿t½kKÞ5àkHLÓKƤôˆsî‹K~ƒ±;_x½r|Va¬èë­¢DÛ[e‹õÄLv}¿Ó'½÷·»Þ(ÉróÔ0®^rxtâÉæ–Jå»9›ÁŒµÒ>­ôžv6ö• IkP‘4è‰1šÊ9 \1—vvÒÛé™ó4X54<äÖ¡¹Õr‰ÒÊ6®§'f²oì»9éƒ) Öe"Yn[ëœn;¦—eG<šŽÁŒ5»–^Ô a;³ÐànŸžs´£gÈðÐ ã’$üÃÙTÃŽ³ÚŽè¬quµšîª¯h‡1“ïEÛ“/Ížéе7ZCDò´Õ0é7»í î¡Î¾ŒʱNhšŽ/Ê’dØÈ')§'Æ Æ~¶J»Œ¿WAÖí©L$ÏÍQøzåŽõu/‘È(g÷YÑ,ð°ô²Ò?!×Yx>®½xˆ^o4½cÎx zjœaðhÑŸŠYãxMÿûßÿû·á~ ÷PbIEND®B`‚mfgtools-uuu_1.4.193/snap/hooks/000077500000000000000000000000001417203213400165025ustar00rootroot00000000000000mfgtools-uuu_1.4.193/snap/hooks/configure000077500000000000000000000013261417203213400204130ustar00rootroot00000000000000#!/usr/bin/env bash # Configure hook to set up configuration when `snap set` is called # # Copyright (c) 2021 Snapcrafters # lint: The use of backticks in the printf messages is intended # shellcheck disable=SC2016 set \ -o errexit \ -o errtrace \ -o nounset \ -o pipefail disable_snap_confinement_warnings="$(snapctl get disable-snap-confinement-warnings)" if test -n "${disable_snap_confinement_warnings}"; then if [[ ! "${disable_snap_confinement_warnings}" =~ (false|true) ]]; then printf -- \ 'Error: disable-snap-confinement-warnings must be either `true` or `false`.\n' \ 1>&2 exit 1 fi else snapctl set disable-snap-confinement-warnings=false fi mfgtools-uuu_1.4.193/snap/hooks/post-refresh000066400000000000000000000001721417203213400210460ustar00rootroot00000000000000#!/bin/sh -e echo "test" > /etc/udev/rules.d/test uuu -udev >> /etc/udev/rules.d/70-uuu.rules udevadm control --reload mfgtools-uuu_1.4.193/snap/local/000077500000000000000000000000001417203213400164515ustar00rootroot00000000000000mfgtools-uuu_1.4.193/snap/local/LICENSE000066400000000000000000000020551417203213400174600ustar00rootroot00000000000000MIT License Copyright (c) 2017 Snapcrafters 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. mfgtools-uuu_1.4.193/snap/local/bash-completion/000077500000000000000000000000001417203213400215355ustar00rootroot00000000000000mfgtools-uuu_1.4.193/snap/local/bash-completion/universal-update-utility000066400000000000000000000001451417203213400264510ustar00rootroot00000000000000_uuu_autocomplete() { COMPREPLY=($(uuu $1 $2 $3)) } complete -o nospace -F _uuu_autocomplete uuu mfgtools-uuu_1.4.193/snap/local/launchers/000077500000000000000000000000001417203213400204355ustar00rootroot00000000000000mfgtools-uuu_1.4.193/snap/local/launchers/universal-update-utility-launch000077500000000000000000000046351417203213400266340ustar00rootroot00000000000000#!/usr/bin/env bash # This is the maintainence launcher for the snap, make necessary runtime # environment changes to make the snap work here. You may also insert # security confinement/deprecation/obsoletion notice of the snap here. # lint: The use of backticks in the printf messages is intended # shellcheck disable=SC2016 set \ -o errexit \ -o errtrace \ -o nounset \ -o pipefail #export IMPORTANT_ENVIRONMENT_VARIABLE=value # Run the command, if fails, check and present security confinement # warnings to the user if ! "${@}" \ && test "$(snapctl get disable-snap-confinement-warnings)" != true; then snap_confinement_warning_triggered=false if ! snapctl is-connected home; then snap_confinement_warning_triggered=true printf \ "Warning: It appears that the %s snap isn't connected to the \`home\` interface, accessing files under your home directory will not be possible.\n\n" \ "${SNAP_NAME}" \ 1>&2 printf \ "To fix this problem run the following command as root:\n\n snap connect %s:home\n\n" \ "${SNAP_NAME}" \ 1>&2 fi if ! snapctl is-connected raw-usb; then snap_confinement_warning_triggered=true printf \ "Warning: It appears that the %s snap isn't connected to the \`raw-usb\` interface, direct-access of USB devices will not be possible.\n\n" \ "${SNAP_NAME}" \ 1>&2 printf \ "To fix this problem run the following command as root:\n\n snap connect %s:raw-usb\n\n" \ "${SNAP_NAME}" \ 1>&2 fi if ! snapctl is-connected removable-media; then snap_confinement_warning_triggered=true printf \ "Warning: It appears that the %s snap isn't connected to the \`removable-media\` interface, accessing files under /media and /mnt directory will not be possible.\n\n" \ "${SNAP_NAME}" \ 1>&2 printf \ "To fix this problem run the following command as root:\n\n snap connect %s:removable-media\n\n" \ "${SNAP_NAME}" \ 1>&2 fi if test "${snap_confinement_warning_triggered}" == true; then printf \ "To disable these warnings, run the following command as root:\n\n snap set %s disable-snap-confinement-warnings=true\n\n" \ "${SNAP_NAME}" \ 1>&2 fi fi mfgtools-uuu_1.4.193/snap/local/screenshots/000077500000000000000000000000001417203213400210115ustar00rootroot00000000000000mfgtools-uuu_1.4.193/snap/local/screenshots/carbon-help.png000066400000000000000000002306001417203213400237120ustar00rootroot00000000000000‰PNG  IHDRJÎ9)Ô IDATxœìÝçõÞðñØË9^§—Ûë:¨–ãÒAì¨("¢‚ H¤I B'@B•¢ ˆŠŠJ0j€PB˜á{?3™ÝÙ2ó›²ÉçÁûõ:Çd3»“aË'¿’µúÓí¹«?ýF¬¬Úôµ¾Rjå'©Y±q›Z¾ôÌò [}·l=<÷ñ¤/èϳU@-ÆË¶¤ºƒ¥ÚßTw?/Ú¤]]ýéöÜ,«PZYi&ÄQBhŠ‚~QÎÝ2$¤V–hš™ÁÔ"”†9úG3,Šý¤Aàž ºsQÃNý¦^ÆRS(%ª£•.ˆýd®JPÃM+G0½J35†-Žft úIËcù ús}eŠ©¡ §>EÓ°ÓÕŸnÏÍZ±ñ«aФ¾ Y­Ê!4è'{¼ ûD!5tá4£F™ªéš+6~µ@Q(ÍÑ£!Š£•1†ñ$ºtÝU2°†8œfJ4 C0UJ3 † Œfr%l€ dtT a< :š†9˜º ¥!¤•)ކ8‚ýd +Ô1•hêS0õ-”VÎ@Š0’ôšk€g‚þÜPP k< 4šV’`šf(­|´2…ÑŒ ¡A?±€ðºS8 ©•)œVÕ`šF( a Í´8ês%x€*#¤5 ñ4“¢©·ÁÔu(õni¦Ò ãh(‚hÐOt.,ùh3P,èÏûaª¾ÄÓ¢i˜‚©W£K“„Ò̤¾ÇÑLŒ¢A?A4ÀG! °™O3!š†.˜¦J«f [ÍÄô*¨z21¢†-œL-Ciˆ"i%‹£ž‡Q¨|ðÑgÀgA÷€PÕ°†Ó°FÓÆÒ˜PZ5©_q4“¢(a„E¥ ©ÆÓ°FÓÌ ¦Q¡Tm$­4,q4CbhÐO¢¡Qð)þ úspHdLDÍÐhšIÁÔiçtJ•Ž" S UGƒ £•>‚ýRtGð8¦†-œzMÃLUŽ.uJ3!z9zTù¨Ñ€ƒ(¡„V†ÆT?é²Ñ¦Ž2 *˜zJ+] jÔh@Q”ðYañLПßÃV‹§A6­‚Á4åPD$ k {­ 4è³¼5›¨4‚þœŠ’€êG8­ÁÔ§Xš4”Vš@ò8XÍ àô p.£k@µ²DÓL ¦ C©’HêA õbô¨ë8ö0‚ô2È\¡ª•(œºŠ¦Œ2õ*˜¦KmC©Ÿ‘4c©‡a4È šÑñóÃO€ß‚î.¢jÕÓpZÙƒ©±Ô2”fì(Ò Ž£~GÑЅРŸÐ@ðBRýާ•=š†qt©m(ÍØQ¤^Râ¨_Q4ô“j ­Þ’úó{PqÕ³€êQ8UM3.˜*]j„Rב4ƒ©êÑ£žÄQÅQ4#hÐ/À;™S•ÇÓ £©ÃQ¦•!˜ÚwЯd-ßðe\( j©ª@êõèQåqTQ c ú‰×­…«¨<‚þœÊÀêQ@õ*œM2ULý]º|×ñ¡”@ê<ŽzF•GÑ  A¿˜€ôetP 2ž* §Óä±4.”fj$uHCG•…цРŸœ½µ€ýy8ó"«ßÕu8 Y4uLCK£B©ÊHT õkô¨Ê8ª$ŒC‰’ ZæFU?â©«pª(šz5Ê4TÁ4Xj„R?G‘†5*=ê0ŽzFÃAƒ~ÂÖ‚•ë°ôçÖà…/¦úNUES%£LCLUŽ.]¾áËYùë·. Í(ÒR¯âh˜¢h¦ÇÏ _¼TÈ]ñ1  úsifÇÝà"ªWñ4¨hÆ`ê×èÒüõ[&¥™:Š4à8êxÔ¨‡Q4Œ”È@åîØê_@UN6õ:šfêèRW¡ÔHª2z=z4À8êOõ?|ý$ëUZПKÃ!˜°ê}@ s4õr”©ß£KÝÄÒÄ¡4“©—#H½ˆ£†Qï#(‘€ª(œQÕ¯ˆêw8UM3i„©ë`šr( x©_TõèQ¿â¨×Q4˜ô¹wæ/@ ?çfZhõ&¢ª§^DS/G™úL}]J½Ž¤iŒ" c UGÕ†Q5A4ÃgÐ/R 3꺀êc8UMCLÝŒ.UK£Ci¦Œ"õ"¦1zÔë8ª:Šª¢DÎùË×ɼek­ ?7‡'¶P݇S•ÑÔ«iù¾¬_êÃTüŠP’H¦@šÖèQÏã¨ó(D %VPueNTUPU…S/£©ªQ¦^Ó ciy(]÷yÂPêÕT{£H½¤^ÅQU£FÝGÑ`#hÐOÜ å@åôçnŸB«ÕY8u7ÚTU4õ5˜ú0ºÔM,Í_÷yâPêG$U=ŠÔI U5zÔËQ£îF‹úC ˜`^þG¡ª^Tg£N=Ц*F™:¦AŽ.uK†Ò@G‘†-†$ŽªŽ¢FРŸ¨ó?’¹ù FП×UVïª#Ný¦a ¦~Œ.M+”†q©WTõèQ7qÔ«0êk yМ³¤*ôÖLjL8uM=–¯2˜8º4¥PX$U9ŠÔ£@ê|ô¨Ê8ª.ŒB ›T]¾ÇUªŠpª*š:eêQ0õjt©×±4.”ªŽ¤¾"uH•M-Žº £žDQ"¨¯O¾KÖ¯„(®úQÕÅÓÔéêhêvZ¾çÁÔíèR—±4*”:Ф" C u6zTEuF½ ¢¾EРŸìS0{ɇ„VП›ýŽ­JCªÂxê&œº¦*G™†!˜º]š,–¡´²ER/iPqTIUCÃ>ƒ~áÂV•DTñ4lÑTy0ÍàXš¿îó…YKÖnY¤*’ºÙÕÞ·Q¤R¯ã¨ª0ª,ˆV‚Ø9ëƒÕTyA>"¦º ¨.é·ÑÔ»`êÛèÒb©“©øvtÉÚ-‹,C©g둪EšÑÔƒ8ê0ŠúC š 4AÕe@uOUGÓL ¦¾Ž.McÝRËP†HêÇ4ûô©¿qÔíˆQÇQÔÇêÛòâð™™· €¤‚þüj)âªW5ípêp´©ŸÑ4­`êÃtü ci\(õ3’ªEšITõ¨QGQÔãdä úE €ª$ÈØêyDUO•FÓðSÏF—zK£B©'‘4¨Q¤Ò0ÅQUQÔ—š!±sFÞJ*½ ?{V= ¨i„Ó°DS?ƒiP£KUÄÒÔBiP‘ÔÉ(Ò4Ö!M5:=švU5jTQUA‰™T¾GU"ª›pªb´izÑÔé(ÓÔ‚©“õKÝŽ.õ+–F…R§‘ÔÏ©öªF‘ª ¤ Fª5ª Œº¡=­Ne@\uQý §éFS£L= ¦ŠF—ªœŠŸn,½J7[‡R#©“©öa ¤ªF¦G]†Q§A4°ô …œ…„_ПŸ½ ®Ê"ª‚xê4œ¦M=eT0õd*¾ÂXºdíf›PD$õh©ßÔï8ê*Šº ¢aŠŸA¿øP•…)ªzP‡SŸ¢©ŸÁÔïÑ¥^ÆRëP²Hêvécä…–äÁÍ¥Þµ5$’U @ þp»´¼å>y¡eÜ´ï£KýŒ¥ñ¡4‘4ÝQ¤vtøÐ‰Òôß ¿ €Ê é¿ʨSS¦éŽ. 0–F‡R¿#iºSíÓEÚ³Ó[¹,ø‹¨T.«&½^îïjtiºSñýˆ¥¡ÔÃHêÅTûD›5õêôVð P‰õìÔ/½Íž<˜Š¯2–.Y»yQÖâëPšn$õk=ÒD‘tä°)¹ì¦À/ R»ì&>dbà±Ô2˜:ˆ¥‹ lB©_‘ÔíT{ó®[s—H“¿Õ þ"ª€{ÿ^Wæå¯jtʧâûK-C©þͶ¡4€Hšh©npÿÑ_@Uòî[ïÇu:'£KýŠ¥æö™0”úILµ=ñå6Hûfí¿0€ªä¹fÏÊÂU,›Ò©øÇÒ¨Px$Msª½Hu÷ÿß=_@Urÿÿ5ŠjtiÇÒ£KýŒ¥F(M7’:ÝÝÞ«HºpÕið‡;¿0€ª¤ÁîˆëtAÇR«–™,–Æ…Ò0DÒtéÂUdÁÊõ_@U´`åzËfçv*¾Ÿ±tqÁæEYyk6åej$]°r½,X¹^rW|øTE¹+>6:]¦ÆÒ¼5›òìCiERB) ½Ïej, ¥™I ¥@0Ì.Sciy(]<”†%’ZÒrë¿ €ª(wź¸^gLCKcCéj«Pš$’Z†RO"iòQ¤z$%”ÁÐû\j±tƒ/±Ôªi&Š¥ñ¡4 Hêdª}Å/€P %¶Ó¹ŠD,¥NÖ% I$¿œP aþòØPÞXj·^iÂP–Hj7ÕÞI ¥@0ô>—(–êÁ4”±4*”f`$Õ„R 8±.ciÞêMyY W}²8L‘4Ù¦MV‘tÞ²µ_@U4oÙÚ´ci|0 6–.\õÉbW¡4èH:oÙZCÐP™]¨b©›Pªd4©ÒHj½il$%”Áˆítö±4•MžœÅR·£J£BiÆFÒüd^þG_@U¤÷¹LŽ¥F(õ:’ƇRµ‘”P ÃÜ輈¥±Ñ‹Xê(”¦².©ß‘tn~AàPÍÍ/6–*X¯´<”®Ü°8Ó#)¡†Þç29–.\¹!:”z».醸Pª*’ÎYJ(‚0giÒXÛýX¯4q(Í HJ(‚¡÷¹LŒ¥–¡Tå”ûd;Ü«ˆ¤ú/€P '¶ÓyK7¦KNÁ7Bi*S¤»¤KÖÈœ%k¿ à­z×Ö×Û½"#‡ììlå^o÷ŠÔ»¶Fà3Óè}Î},ýسXšl ¾u(MsʽªÍ›ÜDRB)@å׳S7Oil, úqfs£SKUmî”Êü…+7,ÎÊMJU­Kêu$½äÃÀ/xK™­ª7Vþ³[Uo,ÙÙÙ2røå?{`ŸòΛý•ŒV­wm yçÍþÒ¯kïÀºÙK> E,M{½RSÍ ¥Ê¦ÜûI ¥•ŸJ3íç÷ëÚ[²³³]ÇR=’fgg‡.”†2–¦1?:”º˜rït‡{U‘”P Pùej(­wm Øg€«Xjޤû ÕZªæFçe,íŽéÆÒDSðmC©ÊuIýˆ¤³>Xøoej(d¹‹¥aޤ‘¬j2ëƒÕÅREë•F…R_¦Ü{I ¥•_&‡ÒH–³XöHɪfô9¯c©—Sð-C©Š)÷©®Kš(’F…Ò$‘”P Pùez(d¥K3!’F²ªE5ºd±Tï~Éb©—ë•Z*Í]¹aqÖüë>|ʽËH:k1¡ ²« ¡4’•Z,Í”Hɪ&³¯VKƒš‚?źâB©Š)÷N×%‹¤¦Pš(’ÎÌ[øoU–PÉJK3)’F²ªÉ̼U©ÅÒ˜)øQ±Ô£õJS‚J½™r¯f]Òd‘”P PùU¦Pɲޥ™I#YÕŒ>ç$–¹^©yTi\(µ‹¤©„Rë’:¤„R€Ê¯²…ÒHVL,íÓßøß™I#YÕ¢±4õõJS¥±4*”ªMêf]Òd;Ü'Ф3òV~AdŠ~]{QP•~]{{~¿+c(d]Š¥}ȸqã$;;[õ};c"i$«šÌÈ[™R,µZ¯4Q,õc ¾ÞEËCé²òPšÉ‘”P :Bi0?ߎyT©>²4ÓBi¦ÇÒùË„ÒDSîÓÞ¼Éa$±hEà¼UC©yMÒA}ß–}­7x ³‹V¸Ž¥éoîär ¾](õz4©’uIí")¡ J¨l¡Ôjã&« ž‚>ïɘCi¢Xêõz¥nF•Î_¶îƒ¬9ù-IJ•írï"’šCil$%”T~•)”&ÚÝ>Ób©Þç¬b©ÞõÜÆÒdSðãG•ZÇR»P:'ÿ£%Ñ¡TÑhÒT¦Ü;]—Ô*’æ,$”Tv•%”&ФæïÉ”Xš³pEòXêt½Ò4§à;UJ}šrïf]R»HJ(¨ü*C(M%’š¿7b©ÞçTÅÒTÖ+U=ßq(U6åÞÅæMæHJ(¨ü2=”¦IÍ· {,57ºØXêfs'5SðÓ ¥O¹Okó¦E+âBéôË¿ à­L¥N"©ù¶aŽ¥Ó,¥)ÄÒ´Ö+õx ~¡Ôç)÷v›7ÙDRB)@å—©¡ÔM$5ÿŒ°ÆR½Ï¥Kí6wòk ~âPº´"”*Mª`Ê}¢uIõ_¡ òËÔPªN§‘TgŽ¥ýºöü÷¡37:/Ö+M} ¾óQ¥s–¦JÕŒ&u2å>ÕH:}Á²À/xK™­ª7Vþ³[Uo,ÙÙÙ2jÄHå?»_×Þ®#©N¥á ¥Ë\ÅR·SðUŒ* ¥*6pJgʽ“uIÍ Ãš#é´ÜüÀ/x«g§nF,õÊëí^ üqfši¹ùQ±ÔÉæN‰b©Ó)øélì”B(õqʽƒuIõHJ(¨üê][Czvê&£FŒô,’†iíÏL¡÷9«Xªr½R•SðmC©—£IM¹w·.é2B)°èPš –:Y¯ÔåüTG•& ¥ÞŒ&u3å>v]Rý—0u>¡ÂÔùù–£JÅR§Sð½U:géGK²f/]³$ÐѤI¦Ü'Z—T¤„R zŸK4?Q,M:߇Q¥³—®± ¥îF“:ÝÀ)ÝuIõ_¡†¹Ñ¹Z¯ÔÅÆNnG•F…R×£Inà”Þ”ûŠHJ—~AUÑÔùKãBiÒXšâ|';9UjJÝ&uµSë’ê‘”P Cïs‰F•¦KÝnìäfT©J½MêÝ”ûò_”yK¿ €ªhʼ%)ÅRÕSðUŽ*µ¥>&u1å޼桖U(M9–¦;ߣQ¥³—®Y’5kñ‡K“‡RÿF“¦;å~ʼ%„R zŸób ¾£J­Bé¬Å.µ ¥~&5"iÚ£I£#éä¹~AUÑ乤KíBi²XêͨRËPêÝhRç8ÙGRB)<ëPê,–¦»±“ªQ¥–¡ÔõhRýΦ:š4&’:MJ(‚¡÷9'£JÓ‚on*G•šB©£I«MI'ÏYøTE“ç,vK†Ò¦à«UJ¬\oJýMêdÊ=¡NâPªn ¾ÊQ¥z ¥«–¦:íÞÍhRýÁy1št¡Ĥ9‹=UšêÆN©*µž~?kñªD¡ÔãîFRB) ½Ïy:?I(u:ªÔ2”¦<š4É´û F“J€`xJ*5µÌTF•&¥É7q ÓhÒ‰³ó¿ €ªhâ켌UšhS'#”&ÛÄIÅhR#’¦JÓ¤„R zŸK7–¦JÓ¥éŽ*Õ»hT(Mg§¹ùÎC©£I ¥@0œ†R/F•êÝ2ÝMlBiš›89X›Tu$8kQàPMœµÈ›Xªp­Òd›:ÍZ¼jiVNÞÊütF“ºšv¯`4©U$%”ÁÐû\\, pT©¹e¦2ª4'oe~L(Ms§˜HšN(U9š”P Ã6”ºˆ¥é„ÒtG•ZmêdJUN»w;š4•H:aÖÂÀ/ *š0kaʱ4Q¥)L¿/¥ W؆҄‘ÔE(U2šÔI ¥@0ô>gŽ¥~* ¥©*½J®0‡RwÓîƒMJ(‚aJÃ>ª4vú½e(‹¤ž…Ru£IÇÏ$”A?s¡òQ¥^…R»Q¥©…Ò&?“P Eïs™;ª4*”ú?í>ÝѤvSî ¥@pÌ¡Ô.–¦7ªÔÿé÷q¡Ô.’:¥>&?cAàPŸ±À×Q¥ŽCi‚Xšr(õjÚ½ªÑ¤Ù9¹_@U”“«tTiÓïs®ÈÏšîS(õr4)¡FvN®ç£J½¥ÓÍ¡ÔÕ´{W›8¹MJ(‚¡÷9£JÝlêäfú}J¡Tí´ûÄ£IPšæhRB) #”¦9ª4ù¦NË|›~ï](Ms'»Ñ¤F(M2št\ÎüÀ/ *—3?¥Q¥vÓï+b©O›:% ¥q‘4…PêÙ&NF“J€`D…R…£JÝlê”J(5ÇRûPêã&N*F“J€`è}ÎQ¥^M¿÷&”ºÜÄÉÉhÒqÓ ¥@ÆMŸïlT©‚M”†Òi¹Ë—9¥Š6qr;š”P C¥nG•ªÚÔÉI(–»|™JÃ4í>ÝѤ„R zŸKwTi˜¦ß«¥lâ;šT¥æÑ¤„R æPªÇÒØPjÄR6u >”1í>v4é¥P:vÚ¼À/ *;mžõôûK±4¦ß¡Ôˆ¤V¡Tù´{÷›8ÅŽ&%”Á0Bi’Q¥*7ur:ýÞ*”Î[¶Ö"”†eÚ}š£I ¥@0ô>çvTiÓï]…R7ÓîUnâD(‚J}ØÔ)éô{?B©ŸÓîSÙÄIÿ%Œ™67𠨊ÆL›k;ª4åM<œ~ŸF(Í_æzÚý¥PêÛ´ûé„R âB©Í¨RϦߧ¹N©U,–›ï.”&žv¿\ù´{«MœÆL›K(¢÷97›:¥>ýÞ~R=–úJ˜vŸh'B)s(µÝÔ) é÷ž„Ò0N»× c¦Î ü‚ª¢1SçØŽ* Ëô{G¡4íõIÓ˜v¯‡RÕÓî ¥@0…R7Óï­Bi²é÷é¬SjJ•¯O;íÞz}R%Óî§Î‘ÑS¥@FO™cÄRo¦ßdžÒeÊ×)M?”ª\ŸTá´{B) s(õrú½—딦JU®OêvÚ}ì&N£§J€ è}.Ù¦Nª¦ß{±N©}(õ`}ÒØi÷V¡Ôé´{B) #”*˜~Jí§ß»_§4.”N™»t¹·ë“z?íþýɳ¿ €ªèýɳ›~¯jÒ)s—.O+”ú±>©“i÷„R z(u;ýÞ“uJ= ¥¯OêfÚ}ØCé¾={EÓÊdx×w¿/€JQ¡Ôƒé÷*Ö)uJ½\ŸtR²Pšæ´{B) ½Ï¹š~o ¥“üX§4¥Pêj#§Øi÷¡4õIÍ£IcC©y4)¡†9”ÆN¿7‡ÒØé÷é¯SJí×)MwC'#”ºÝÈÉ÷õIc¦Ý¿?yVàD¬{þç¿2aÀ(Ùñåv)++M+“ÒÒsRøÛ>ùúÓ/dæˆÉrÿ¿ë~?7ÞŸ<+­é÷~®Sšê†N©‡R›õIíB©ÒõI§Û‡R½V‡-”¶¾ý9¸ÿwÑ´²„ÚD ü¾nè¡4vú}T(~ïÁ:¥¶:¥°N©ëPšÊFN~¬O¦PZëò›äçv1´`Ñréùä«Ò¾áãҡѓһM™óþTÙñåv©uùMß_À »Pêõ: ¤Vœ IDAT¥*7tJJý\ŸÔÍ´û0…ÒNÍÚ‘tñÔùßÀKzŸógú½ûuJÓ ¥j6ròv}RóhÒ0…Òa¯¿m„Òîu ä>4ý{™6$[¾ßú?&¥¥çää‰ã²ï/²í“-2olŽÜ÷·Úq·ëÒªƒÌ>I>[³A~Ù¹[Ž9"¥çÏJñ±còÕ¦ÏeD·RǽïoµeñÔùòýÖo¤ð·}rúd±œ?wF(”uKVËk¾`{Û.­:Hîø™òõ§_HÑï…röL‰”ž?+‡ÊÚVIׇ_òôœÕ½ªº¼ÜüY™:xœ|¶f½üºkœ*.– ÎËÙ3%r´¨H¶oÞ*½Û¼u»Aú¿ïÖ·5·üÙß~þ•hZ™ìض]ù9wC_¢`ÑrÛ߉þغ>}þÝ>n7Çáb¥ §ß{¸N©£ †R6rR±>i¢i÷£&Í ü‚Ð yµŸxÆõîûñŸúoK9ZT”t}ÔÆº+î¶;¶mOz»ï·~#n¸ÃòØÍÿY/éíç›ayÛT޽qÅZ¹û·{rÞÖ~°*éñ5­Lúµëu;·ÁÐí9wƒP T5i¦³é÷.Ö)U¹¡“)”.YžlÇ{ß6rJa}R«i÷a ¥Oý·¥xΔœ–>ϼîëñúæ;Ñ´2)-='óÆæH·G_’çï~B:Þ÷Œôk×MfŽ˜,Ÿ¬\ky[=Ú.,”ì~Ã¥_»nÒë©Îò~Ï!²ûûǵhÒÛã/ÍÉ•a¯¿-[>/í¶–Ž÷=#Ùý†Ëñ#G*—ÅèPýØG”‘o ’^Ou–žO¼"cû “}{ö·Ý´j­D.SÞÖ/+M+“sgK¤ o¥Œí3Lúµë&¯=ø‚t¬£ êø¦,œ8[¬Ö8êvªB©›sPJc¦ß»\§Té†N B霥2eî’B©W9™¦ÝdžÒt×' S(dU“¹c¦GüñëoeÈ«ýäî?z3R×òï6Ž9eÐØ´o¯G»o?ÿ*îk ¯¿M~Ù¹[4­LJNŸ’×ÕLëg?yg )=V4­LÖ,\–Ö±\WS¶|ô‰ñØú´íªüÜé¡tßž½iÝNU(õâœ'C(*؆Ò§ßG…ÒØé÷>mè”0”Ú®OjJýÜÈ)vÚ}ØBi+o‘œ÷&Hi鹨`zòÄq™76GZÜØÐ“ã>ðÿêÇš>t|Ú·Oí"YÕdTÁÆÏþî'Òþù_mú\4­LvÿcÚÇnú÷:Rrê¤hZ™lßò¥òsÆPªâœ'B(*è}οuJc7tJ=”Úmèä,”ºÜÈÉ<í>6”:]Ÿ4l¡T÷X¦2Ü )>v,*˜ž=S"ï½6À“cîÜþ½hZ™”••JnöÌ´¢l²h÷Ò½O!vS#+u¯ª.ÍÿYÏXWtÕü¥¢ierpßþ´m¾ý… ç¥Ñ w*=oa ¥éžótJ€ ÉBiªë”šCiìô{Õ:¥JÓÙÈ)•PêÇú¤#'†3”êê_[Stè!?ÿ°3*˜íü–òcµ¾­¹Ü·ß8Æ… çesÁFyë¹îR÷ê[Þ6Y´{òÎÆÏÔñMËïy¡ñSR·RJYY©ñýG‹ŠŒuJîÿ=ícG²ªÉè^CŒŸ×&ò ÒóÖPšÊ9wŠP T9qf 딦J“nèdJìx¯b#''듆=”êj]~“Œí3Ì@§Š‹=ÙŽñŸî’éCÇËÑ¢¢¨0[ô{¡Œí3Ì6˜&‹v­ok^í:õûúÄ·ß:ž§¡ôÝ—û?ã¥{ŸVzÎÂJ“s7¥@…„¡ÔÉ:¥lèdJ/ÅÒ)s—,Ïš4'q(uºã}ª9©XŸ4SB©®`Ñr#unñœgÇ©wM éÓ¶«l\±ÖØHIÓÊä»/¾–ƺ+îûÝD;óñ¢ß å{I‹HÝ«o•F7Ü!­o¿_¾øøSW¡t€QÆ1ÚÖyDé¹rJßy±WÒQ®a ¥¿ÿú›hZ™|œ¿Æòë‰b¥ÛÇíæØ \ôPêÙ:¥inèdJgæ­JJ'ÍIJ3d#§L ¥ï÷¬˜B®zÝI;ü¿úÆŸšV&K¦Ïû7Ñnñ”yÆÚ¨ß|¯åí—Ï^ì*”æÏ\d¿É_"JÏÓPÚë©ÎÑ»åó–ßÖPºûûEÓÊdû–m–_O+Ý>n7Çáây(U¼¡“‡¡4õœ…R§9œ®PZçÊ[$rYâïY³p™ÚÕS;22™í[¶‰¦•Iá¾q_síÖ~°J4­LJN´=¶›Pz÷o—“'Nˆ¦•Éž?)?/NCéÓµ2ÎÉÄ·ß·üž°†Rý1—œ:)õ®©÷õD±Òíãvsl.zŸS½¡SâPšÂ:¥*B©ªïýÚÈ)L¡´OÛ®òËÎÝ2þ­Ò¾áãÒäÏ©}ÅÍRÿÚšòÄȬ‘“´ûû“FÕt=yg‹„_ß¾y«'¡47{¦ñµçï~Âòö©„Ò_w푆×ß÷õycsŒŸÿ~Ï!ÊoNCi+o16©*ümŸå’a ¥£z 6~ö¨ƒã¾ž(Vº}ÜnŽ Â%>”†kC§ØPªÇÒP‡R§9œ8#ð Bg^4‘ãGŽ(ß¹ýá›ïM+“]ßý S•îu”çï~B:Þ÷Œôoÿ†lZ½Î8~þŒ…q·wíž¿û ¹xñ‚hZ™;|X¦ +¯=ø‚´oø¸¼Ø¤t{ô%#Ò& ¥ú§3GL–·žë.C»ô—­ë?3¾¶÷§ÝRÿÚšÊoNCi$«šL:Þ¸¿îÚ#£z –­_–>ϼ.£{ ‘Ã……¡ ¥÷ý­¶?f,™?s‘ô}¶«ôhý² ìØGVçæ'Œ•n·Ûc€ð9qF`:yJ½Úñ~’¢Pj·>i˜Bi»zÈòÙ‹åÈÁƒ–ôÈÁƒ²pâliqcåÇîûl×”"íž?I³Ô»½Ûh—Ýo¸KIJíìßû‹íú§n¹ ¥ ®«)_nØœôþ‡-”F²ªI÷Ç:FmôeÇ*VºyÜn ÂÃJݬSjJc7t2‡Òt6tŠ ¥F, ¥6;Þ; ¥~ïx¦PjÖìuåñšÍäà¾ý¢ie2¶Ï0OWÿÚšòÆãdùìÅòã×ßJÑï…RZzNΞ)‘ƒûöËgkÖËÐ.ýmGdªˆvíê?*Ksre×w?ÈÑ¢")-='ÅÇŽÉo»–í[¾”•s—Ȉnm½ëÛ2ñí÷e×·;äLÉi)9}Jv}÷ƒLzg´Üý‡Û=;wnBi$«|*úˆneû–/¥øø1¹pá¼”œ>%÷í—mŸl‘Üñ3-ƒ_С4’UMž¸ãY1ç)ümŸœ;["¥çÏJññc²ûûå£Å+e\ßáÒü_õ•>nÇá *”&\§ÔJ­6trJ—¬IJSÙñ>i(U¾‘Süú¤a ¥º}{öЦ•Éð®ï~_Â*•]ï>z(µ›~ï݆Nö¡ÔvC'G¡4¥ï—ǬOêM(M¶‘Óˆ 9_‰J“#”d¦rÜoèä2”–ÇÒBébÏB©ýFN±¡ÔñŽ÷)läD(Í|„R€ÌTJSßÐÉ2”¦¸¡St(MaC'OBiÀ;Þ'ZŸ4ì¡ÉJ2Sl(õbC§É 6tJJ/ÅRG¡4v#'B)ü@(ÈL™JõXê:”&ÚÈ)6”:ÝñÞz#§Ù–9J€`˜CiôôûøP5ýÞ"”&\§Ô&”Úmèä8”Æîx¯‡Róú¤©„Ò 6r"”ÁÐû\Ð:% ¥z, ¥z,%”p¥Ò„Ò‰³óV¤J£×']³>©}(U¹ã½Õú¤ÃÇOü‚ª¢áã§'\§Ô¥¦uJ-CiŠë”Ú…ÒòXº<~ÒBéÄÙy+lCiÔú¤‡R·9J€`$ ¥ª7trJgæ­J3”ÆnädJóã=¡†ß¡ÔjC§ŠPº,y(]\‰BiìŽ÷„R ±¡4zÒÊJM9¥J“mädJõ…]£C©ýFN„R z(M¶¡“J£Ö)µ¥ 7trJ/ÅÒ´BiìFN¾†R;ÞJ€`¤JGO±¥Óƒ ¥z,uJõQõPj»‘S ¡4áŽ÷ICé B)°èP:Ãq(ÍÎÉM+”Zm複R=–†#”^ºóŽCé¥i÷æPj·‘¡†Þçmèd„RÓ:¥ŽBé¥XêY(ZŸÔJÍ9)¥—¦Ý›C©Óï ¥@0R ¥É6t2B©iC'Õ¡T¥±¡tö’ý ¥ªw¼'”á¡"”Æ®SªwD=”ê±4”¡4z#'ÿB©¾ lT(Ížøäj_qsà÷à:WÞø}àáÙÓâBiô:¥þ…ÒòXêq(Þñ>6”.õ=”š7r"”†[Ãëo“‚¼2kääÀïK"õ®©!/ýPNŸ,–‚¼•R÷ªêߧʨw›.¢ie–Þy±Wà÷/Hß|¯,š4G¶}²E:5køýA…®¿$‡Já¾Ò¹eû¤ß¯ò:O÷Øa±hÒY>{±Ô½úÖ@ïGÖ/˧~,G‹Š¤ôüY9t P¾ýü+™;fº¼úÀsŸ'¸Çëwê«ÑTòg.’ï¾øZ:5}†s^ÉíÙñ“åëÐï¿þæùïû‘ê÷IÞä¹²í“-òÒ½O~.Þ3‡ÒòXêw(]jJXê4”Fmä”f(ÕwžrJõ¯¢CiìŽ÷„ÒLÑè†;å»/¾M+“‹/HÛ:~Ÿì êøfԛȾÏv ü>UF„R{]Zu0ÎE×G^ üþ ÂÁ}ûßÍ/;w'ý~•×yºÇƒWîogÜç/7l–†×ßÈý˜76Çö÷ ieòÃWÛ?Wp×ïÔu}ä%ãt¼ñ=õ¯­iûófŽ˜l|ŸS:G¾1(êMàWû~+£&ŽH»zú<óºo¡4,ך¿BiÛ:È€=B?š®Î•·çcæûéõ¯­i|ßô¡ã=yÜÅÇÇ8\X˜ôûU^çé; ¿ïºWß*ë–¬6î÷–>ñ}d©ùßÓ‘ƒet¯!Ò¹e{éÝæ5óæ{²~YäfÏôõ>Á¼~§NU¼âœg†'îx êµè‹?uJü¾ ¥ê¼ùôkráÂy)9u2ã×¹òÙ\°Ñø}>]ë¡Ð»þµ5ePÇ7eÓªµr¸°PJÏŸ•“'NÈŽmÛeÊ»cåÞ¿Öòü¾¾r;ùdåZ9rèœ)9-{Ü%Ӈޗ{þç¿_C^©mM×w¸üôÍwrúd±œ>Y,»¾ûA¦ ɖƺ+Ôçü¹IÁ¢åRô{¡œ?wFŠ~/”óפ4{+èÇfñ¡t†m(=Å"”N¥Q:¥J—) ¥‹Õ„Ò„;Þ+ ¥úB±„ÒpZ6+/¥x–xuÿ¿ëKá¾¢ierà—_徿ÕüVOÞÙ‚Pz‰¡4Õø*C©ÛÇ=ñí÷Ûyó½´oïæ:wsì ßµ¯¸Y6,ÿÈ8þüq3|=þÆkEÓÊäLÉiiù|=6üÅëwêTÅ+ÎyfZûÁ*G¡ÔÉï›PªFÿöoHéù³¢ie…Òü £B¹Ÿ¡4•c·¸±ý^˜pÉ¡…Òú¶æžÝÏ FÉÅ‹,½ÿç_¤Õî üZR­ù¿êÛŽZ×´2)ú=¼ç|Tw¥¬¬Ôö¾Ï›ÚÇvz(µÚÐII(½KõÞ¨$”.vJM9© ¥Ù9¹i…ÒD;ÞJçw›×Œ'‹•ó–$üÞ0Å«†×ß&O×zH\g? ¡´¡ÔÙ}õ#”F²Ê×}è¦&Žnëö:wzì ß ®«i,¿¢ieòÚƒ/øvì£EE¢ie²nÉjß7üÇëwjTÆ+ÎyæqJü¾ ¥î4ºáY4iNT€ "”{ýí¸äW(MçØß~þ•œèÇ …Ró:¥©„Òìœ\oBé¥Xšy¡ôÒú¤„ÒÌÔບRøÛ>Ñ´2ùm÷Ïr÷nOøýaWð¡´¡ÔÙ}õ+”ºáçu¦Çɪ&­þs+_>à×]{üÙôå²jÆH9£§ò¸0"^UmnBiº¸Öœ©mMÚù­¨’§OJŸ©ý°1šU_¶Á¯Pšî±©~Ÿ4ºáޏÿ^ûŠ›£¦î?õß–Jïg+o‘ý?ÿbD·ûÿ]?êëS äýŸ×̃¢æŽ‰o1}Úv5¾îd&–—ç\ zìðá¸A ®«iÄÒãGŽÄ}^ òqgŠ´C©iC§JJË#i¾íŽ÷nCiìŽ÷„ÒÌ0¢Û@ã âõ‡^LúýaWð¡´¡ÔÙ}%”†ÿ÷=´Kã~ ìØ§ÊH–Íʓ۶ËÁ}û¥äô)9{¦Döÿü‹,›•'mîjeù3ÝìLýÞkŒï}ë¹î ¿wëúÏDÓ.mÄb±¡Uã?Ý%ß~_vlÛ.§OKÉéS²÷Ç]2Ü iqcÄ?»åÿÞ-ï¾ÜOòg.’ï·~#G”³gJäÂ…óròÄ ùu×ùxé‡RûŠ›-oßõá—dí«ä÷_“3%§åÜÙ9\X(»¾ûA òVJï6],owßßjËâ©óåû­ßHáoûäôÉb9îŒ:P(ë–¬NyŠm&…Ò¦¯#cz•µ¬’ŸØ)'OœÒÒsròÄ ùé›ïdÚliú÷:IïG§¦ÏÈÇùkäÈÁƒRzþ¬9xPÖ~°J¦ ÉNJžó»ÿx»íuneiÎûûÞ¬­,Z.‡”/”ìðaùlÍéÓ¶«åµí†ÛPêöq«Ú-ØÉuîæØn÷þ½å¥?rð í1ê]SCÎ-M+“5 —%½Oµ¯¸Y~ݵG4­LvnÿÞ“ßé>n»ç¶Z—ß$ï¼ØK¶®ÿLN=*gÏ”Èo»–Üñ3åÁjÞ‡ºWU——›?+S“ÏÖ¬—_wí‘SÅÅráÂy9{¦DŽÉöÍ[ãÞx»Õ¥U™1|’|¶fƒü²s·?rDJÏŸ•âcÇä«MŸËˆn¥Þ55ân×âÆrüÈ‘Koè²&6´ó[¶ç­K«’;~¦|ýéRô{¡œ=S"¥çÏÊ¡…²öƒUÒõaoþèãæõ»É_"2eÐXÙ¾e›-*’óçÎÈÞwÉØ>äåÿÞ-ù3ɱÇåLÉiùôÃåñšÍ¢n?cø$ãX:ô°¾ÿp»ìÛ³W4­L~úæ;ÏFR?]ë!™?n†üðÕv)>vLJKÏɉ£GeïO»eå¼%Ò£õËQßoþ¸~YAù펓sgKäà¾ý²rÞiyPù9d©{ uú¾é…R·¿oóµ6eÐXùpA¾ñÞáÈÁƒòqþéÔ¬­ííƒüL俨n=Rý>9U\, 'Ζ76HVµ@BéÜ1Ó£^ü ¥ªmk/7Vé}Í›îf_{òΖÇèxß3iÿ»Þõã6­o¿_ù¿o¡´ÉŸ#òÕ¦ÏmosöLIùlîƒ!’é×®›ÒÇ®^Häû­ßXNKìöhÅóšÕ¿ý‡njbLû\›ïèØW¬Mº OºÜ¼~¿Ðø)ÛÛêë‹™9t(êƒV+o‘í[¶‰¦•‡‹Øɪø wîl‰í¿#·×ûòÙ‹“žûY#£Ÿ;Sy»pá¼eÌWÎì${ uó¾Á…ÒDr†M´¼}U ¥‘¬jqïQý¥/Ýû´\¼xAJÏŸ•gj?÷ûô2”ª>v­Ëo’—~(šV&ÅÇŽÙŽtJ_‡}×·;l¿Ç¼ž¦êÑÕÍÿYOv|™üuØî³ÿâ)óÞ®è÷BË÷lúÒ[Ön²½oo¿ÐÓø9/ÝûtÜ׾޹9çƒ_égü÷÷7{¦ñ=}ŸíuN¶}²E4­|°&ŽØûÈÁƒ2òAÒë©ÎÒó‰WdlŸaÆÈ M+“M«Ö*uîæõÛJû·CÚÜÕJr†M¬øÝ²E:4zR<ßCΞ)9=cø¤¨Ÿñ`µÆròÄqãÚù5åÕž3®õ±}†)¿Öë]SØ©¢iåqqiÎرôhý²¼õ\wÝkˆ|´x¥t¼/úZ5¿Ž}µés×w¸ôiÛUú´í*‹§Ì3þ°{ª¸8î}‡Û÷Ln_CU¼o©êÒ ¥*ß/^ Ë?ºôœÚE¦''Ž5¾>¨ã›q·¯Ê¡4–Ÿ¡´Î•·Èž;EÓÊdâÛï[þ>½ ¥ÊŽ}YùÌWxN6­Zk¼v'›è„þ:°~YD²Ê׸Ü\°QŠ3®kó絑Ý);vÝ«ªË_UDÒo>Û*C»ô—7ï$o>ýšŒë;ÜŒc÷ٿ瓯Êô¡ã¥Ï3¯Ë‹MÚHû†­¥×Så“•kŸ»ãËøÛêëxîÛ³×öþ™o±£BÝ¼Ž¹9ço<Þ)êõßî¾ëïmbgA¹}ÜnÎy¦ˆ ¥å±4ýPªÇR»PªÇRßC錼•! ¥³¥&a¥ú?ðtþq«ŒWV¥3Ç©)ƒÆ&¼/éÆ ó«ö ·ü}÷½’S'£ßeOÂG‹ŠäÑ[›ÆÝÖ<ÒÇjó‹@ª#xuù3÷KõHŸ'ïla|ØJ6-7SC©ÕµÖ¥U#nÿüÃΨ(PÿÚšFÌ<\X(­þsOÜíß}¹â¯œé¾ñNõœ;Y»Ñ|Î3-.vÔ½úÖ¨ÑUªþZ¶5Jݬíæö:wzl'»Þ55Œ(øÅÇŸZ~¾±BºÓèõ¨^akÌê IDAT·BÉ5¢òqx¾‡q›ÅSãGÿ·‰"7öç¼ùtÅBO™'‘¬jrÏÿü×Xí›Ï¶Z^'nMè?Ò8î¶›¥Ù?ê¦|Ûd¯cC^­xÝkˆ²sžÊ±½†F²¼}ßRUøù:fþ}êÔ7îëVk,GM³Þ4…PZÁÏP:ªÇ`ãu®îÕ·Zþ>½ ¥*Žm5càÐBOÖÉ­}ÅÍÆ1–Ï^,‘¬jò΋½ŒÿV|ü˜D²Êgf$ú<çÔÈŸ›7y®å÷¸ùìo$;sbѤ9Æ×bC¦®SÓŠÙGo>ý,§¯cnÏyóÖ3þ(÷å†Í¶ÇÙ¶qsÅk‘ÂÇíæœgŠÔBé¬P„R=–VÚP:ŒPªäØ*è;Ð-›•—òm¼ŽWu®¼Åø«õæ‚ ïKºoÍK Ì5%îëõ¯­i|°ŽýšŸDÍ#xbé£y¬‚„›Pºdzù›®Ó'‹-G ¹¥O_ÝýýJϹ^_k‘¬j2kdÅm;·loüwóê¡]ú[ÞÖíïTι“€¤¿Yسã'ÛÍ­:5kkü\«¿ž:A(ul§[£VZzNšü%úù¡îÕ·Ê™’ÓŽÎ¥þ‡£dÏ ~];fúëãÑ¢"ixým–ßc~coõÆPɪøð©ie–#õ"YÕäñšÍŒ@þÃWÛ¥MäAc4¥U8NõØMÿ^Çø¹Û·|éÙ9pJ#YÕdï»DÓÊd\ßáÆÝkHÂ{Ks?«w›.Æ4Â’S'à¬RÝ«ªKññcƇ«åIö:V÷ªêrª¸ü}ˆå);ç©;’eÿÉòþ}KUT(µû}{ýmÓ¿Ÿè @(­àW(möºÆŒb7äõ:”ª:¶U(½xñ‚¬_Võ|¯B£î4Ž¡/ùaÞ¼òLÉi©uùMÒøOwÿmî˜éÊŽ¯¾=\Xhû¹ÆÍgÿ—›?kÜïØM°ÚÜÕJ.\8/šV>³²û7¤Å ¤Þ55¤åÿ5’7ï5B²sËçÛºySqÎ?Z¼ÒøZÁ¢åòt­‡¤áõ·I“¿D¤MäÁ¨™z±{®¸yÜnÏy¦V•Cé´Ü|OBé˜isS¥3¥½)Pá䉢iñk‰$âG¼Ò‡ö'Û}ÎIÌÐGêX}0îõTgãçžèÏ5E4­LΟ;#T¿OZÜØÐRþÌEF°ˆÝÉM(íùÄ+Æm÷þ¸Kz´~ÙÕÈ—ºWU—æÿ¬gŒòX5©hZ™Ü·_ù9wÊkí‘ê÷ß3çý©ÆÏ_1µÕjj{$+ý7ÞNÎyº©Ñ w#|æÍ±½NÍ¿ÇÉÇ(ù}JÝÛéã~ý¡ÛÅnVób“6Æ×mÄaE_\?ÑFQ~^;º{þç¿ÆƒD›™™×¦ž3zjÜ×ÃJ_º÷iÛa6ð¥ÞQ64­Löÿü‹ÜýGûÑ{ÉŽɪxnºpá¼òõát*B©¾6°yÊç¨ï–?¯îÿÝòg5¼þ6ùù‡QçLÓìÿ æ–ùRãß‘öíSyÛ¾åKÑ4õètóÉRÿ¾Å‰®¼$czµûG¥XMþ±½­±-’¾PÚâÆÆ÷䎟õ5Bi¿B©~«õ½¥ªŽ]ïšòHõû¤Ã=OÉ€ç{Sïõ×3»÷àúqÒù÷}Ïÿü×øÙóÆæH$«üßùž;åâÅ 2¡ÿÈòÿöçˆñ}sÇXw‹tÝìuŸi7š4Ùun¥ñŸî’&‰Hí+nŽz>¶ZclŸaÆ×“1ϼtó:¦âœßÿïúQK%òÙšõÊ·Šsž ¬C錤¡T¥ªCiy, $”.5Béä¹( ¥£§$¥ÃÇO'”†0”êaI6ÅÝÌx¥¿1ô"ÚMT±³]ì‹·þ«#ÆEN}añtľPº ¥‘¬ŠX«;¸ÿw™=jJÊCý_hü”䭔Å…FdдòYú_âì>\º9çNùq­E²ª£q>Î_cü7ý¯‹çϱ]§/•7ÞnÏyº©Í]­Ò¾Nc?ì8E(ul§»Î•·S"cß$êÏy§O§½y—ù¶*®Uû™Úß?òÄë‡éÔׯ2 k(5_ÉÞx›§}]¼xA^lÒÆÕ±#Y£25­ÌvGu·‚ ¥‘¬òçI}ô­¦•É–>ñìwmÞˆÂj“ˆdRyû8MJÏ7^„³H–õk¨Îíû· -·}í³{ï­k}[sÛÛÚ½ïW-l¡4rY5cwé+ÖF}PZÁPú`µÆÆNVÏ-^†R¯mžšhéŸtÿ}[M×™g¦¤2õ>Ýc·«ÿ¨ñõá]ß±}LÉ>û7ºá™Ð¤üôÍwƾšV>@Ç­–ψd•ÿaýëO¿0€¦•o¢¼¹`cÔú©æÝßÝ¼Ž©:çMþ‘ycsäÈÁƒÑ¯)ûö˲YyÆÿ_0a–²Ç­êœ‡9”ÆnèdJGOQJõXª÷I_BiÎB5¡tüL‹P:Pj–é¡Ts›ÎˆÒiC²ûmµvšÎ<ËSy#¦¿øxí«ÑÔ¸yú}“¿DŒ7VÓ,Ì X§ªÅ ¢~†ÛPÉ*ßtbËÚMQǹxñ‚l\±ÖØmÒÊÄ·ßOé>‡)”úq­E²ªÉ¡å;"šwJÔ7‰9t ÐövÉÞx«8çé$óH´T-ÍÉUòû2¿JôœÒຊP:mH¶’Çm¥*…ÒHV5™?n†hZù(@ó¦.úëH²i¹Vô?B-*Rr¨zÜï«X e`Ç> ¿W¶ZÛ*¬¡Ôh’½ñ6ÿñOÓʤûc];’½þ²“¸—Š Ci³Ô5þ° ieòÝ_Û.Sâ–y$ËSÿm™öíƒ|Ïäæ5ÔÌéû¥Þý¾cŸS ¥ü¥ &ÌM+_f©õmÍã íü–ñ˜{´~YZßÖ<é(ê0[YZzþ¬íg'ÿ¾c7²µ±ÍcÓ=¶ùýy¢×õD×y«ÿÜ“òÈÊdï\WSZýç¹ÿßõ‘þúf’¿îÚõ½n_ÇTóHV5‰\V¾DÐÃ7ßkÌÐ3Ïí×®›²Ç­úœ‡•’P:=>”ê±Ôm(5bie¥£&Í̘Pjþ‹•ݨ‰DOX¿ÿú›hšõ_Ñ#Y‰_˜Ý[ýþÇþ…'‘ F÷ûÞ¿Ö²ý>ýE´ôüÙ¨ÿt(dULS;¸o¿1Zpx×wŒŸõÄÄÝfÃòDÓʤð·}ŽÏ·ŠPªk}[sÉyo‚ìßû‹ñ3KÏŸ•·_è÷½æç¢ß å{I‹HÝ«o•F7Ü!­o¿ßØì%L¡ÔkÍnt„þû>yâ„íqýûVuÎÝŒ´øRoO?VôvÑdU“{ÿZ˸ú”·ÛJU ¥­o¿ß¸í¨ïçZÉìäzÐ×sÜûÓnO¯7×¹þXídâˆÒTCi§¦Ï£#ô{G‹Šâv?OçØ‘¬èçÞ¶uñäJk]~“±a•~Î4­L¦¼›úÌšt˜ƒÁ ŸJûö¡¥ FZ]ש¾oA¹0†R}EìsjŸ‰ÜÛ ~„ÒÂßö¥oÌÆôš1Çóæ{Æm[ßÿ¹Ì©ï·~#šV&»¾Ýaû==Ÿ|5¥ éxê¿-Ÿ™húz¢ëÜ:æü¹3ò`µÆQß³xÊ<Ñ´2)++•‡o¾×òçèZxuÎðãZ3¯a˜›]1]_›QÓÊlÏY¢ßÊÎùeÕäâÅ ¢iÖk,ÆjtÃFK´¡‹W&ýÀülÝŠMÕ¿ÒOÉã¶²fá2Ñ´2)Üw íÛº½ÎÛåãÖãûÞwI䲊çºóçÎHã?Ý•öÏÛ¾e[Ÿª¸Y£4ÆBÛï{°ZcãçfÒ¥©„Ò¦¯cŒìÚ¾åKy¡ñSFøÛ´Êþß_*¡T_k[Óâ—Q%cv¡´s‹ç¤w›.Q£w’…R}¤ÿÅ‹¤Û£/×À… ç¥}ÃÖÊç«<ç*RùžÉÍkhB)¼oA9?_ÇRù}G=§Æ¬Iäg"7Çö‚¡TE›U¡Ôcé=Ô¸mëÛïW÷»¹ôþ¼ôüYÛ5¸ÍŸùTm(ÕບÆ•>ýðcÛﳻΛÿ³žq>ì8™ÿ}¦í òV·5êöuÌËsþä-Œ?¯[²:íû–èq{}ÎÃBu(ÍÎÉ¥—biê¡tYÂP:3o•?¡t’›Pzi#§L ¥æpe‘`–è…Yƒ]rê¤Ô»¦FÜ×½0»=¶ 9ïMHúÄ«C£'û=º×Ëï©{õ­ÆÎõ±k©|Óßü_õŸe72ÍJýkkJñ±òÝûVÍ_nì6Îèܲ½ñ=3†Or}½) ¥×Zìb}DB¢7l©†Òûÿ]qÎlL‘?®µÉǘ~÷]L¿ïçÿn·Žf¢ß*Ϲ>eeun~JçM1}òÄ iú÷:žþŽbé#µN=j»¦ùÍo‡FO*{ܱô*çΖ¤½ˆÛëÜͱÝ<î­_Žºæõ‘ÑŸ¬L<ÒËJÃëo3Öq´{RÅÍ®÷Ç1¦_ÅšôÎ脾36”^Vñ‡ÎGJ‹J$+zzœÝæDÉŽ}÷o7FáîÙñ“gç ×o»Pj%Q(}±I㕾¢ôüYÛ×x·÷Íêy§îUÕ³é $JÅæ‚¢iåƒ(ÚÕÔò{ì®sóÈG»Xé4Ú™¦X;Qù:¦òœßû×ZÆIJKÏI»zéÍ€Iö¸½<çaâ(”^ÚÐÉI(TÕBiy$MJ/ýÂJë\y‹±¡Jáoû,GÜ$zaÕc°ñcTÁq_OôÂìöØ*˜?|$[ÓÃ|¿•ßï},G›Œk„ñsGtõ5•oú#—U3ž¸íÖÆ²3olŽhZùH†M«×‰¦•¯Gi»NÙeÕŒr/\8ïh:®›PúÐMM¾Q0‡ÜØ¡ÜìŠÜŸ¿û ËÛ§í"—U“’S'EÓìGߪ¢òZ{÷åø7}ßr¯ñoðØáÃQo®k]~“ìýi·qXE–Dÿ¾Užs}´ó‘C‡¤Ñ w$=o}žyÝ8ööÍ[¥Ù?êzú{2ùÆ ãØcû ‹ûú}«mŒ‚;rèPÂuÓ}ܱÌÓ¶Ò^gÑåuîæØnwí+n6¦µnûd‹:üaÆ< Ê«é×:'¡ô­çº·ÉŸ¹(nÓµgë>büÙ¹Û22dj(5ÿ;{ãñNƯuùM²}óVãz«ÿÜc{ì_wí‰ÚHA§¿6jZ™¼ßÓúTJ¤ñú­"”6ºáΨbæ?䘟ËNœ­ü±ê”Ö´2Ù¶q³ÜÿïÔGËùžÉÍkh$ËÝû”3¿–è3 Ræâ÷mu­½úÀsrîlùkŠ>kÁüõ ?¹9¶œ†R=¤é:5këø>¤+ý<öݼÝòõG×»McvÕ.ænÔ½ªºñ>©p߸÷Èæ¥gTïbþrógŸ}´¨Hú´í*ÍÿYOê_[Sž®õÌ5Åø7{ßû×Z¦s²Ár£Ùt£]“?GŒõíõÏÁV›E²Ü½ŽyqÎ;·xN~Ûý³q»t5¤ú¸½8çad„ÒK±4Q(Õc)¡´ „ÒHVôÎÚ¿îÚ#£z –­_–>ϼ.£{ 1¦’Z½0ß÷·ÚR|¼|dbYY©äÏ\$}Ÿí*=Z¿,;ö‘Õ¹»ÑZ½0»9¶ µ¯¸Y ÷0‚Jª·3ûm÷Ï2ªÇ»Ò¥Ué×®›äÏXh<©î;÷A_é›þ¬èÝè?^ú¡¼ób/Ù},™>_–L·ŸzüðÍ÷Fí|§ie2®ïð„Çz®ÁcÆ´ M+ßb€QòÖsÝ¥ï³]ex×wdÉôù²m£uXqJWÎ]"%§NÊêÜ|Ô©¯tjÖVÚ7l-]ZuIïŒ6Þ`––ž“‡njuÛçï~Âø;|X¦ +¯=ø‚´oø¸¼Ø¤t{ô%ãÃu*ç\ šV¾pþ€=Œs®zº·ªkíâÅ ²iÕZyïµòÖsÝeæˆÉÆ¿]M³^¿ë¥{Ÿ6®‘²²R)X´\vì#o>ýš ~¥_ÔtØß*Ϲùyâ—»eTÁÒ§mWÔ©¯äÏXh9õØüïâ䉲4'W†¼ÚOú<óº¼ýBO™2h¬|¹a³¼ù´õj§Ýp§B/^¼ Ksr¥_»nÒ¥UÕcpÔ‚èVfÜ>n³6‘Û;|XÆõn<öí[¾Lºæ•›ëÜͱÝ>nó_Èõߢ$v>_W¾ùŠÑÑÚ¬—U,5 iåÓχ½þ¶ôoÿ†äfÏ4"qYY©m¬ÎÄPúè­MåLÉiÑ´2Yš³ þ¶·?`LÁ·ú€©[ÓÊ—+™9b²¼õ\wÚ¥ÔZ\{Ú-õ¯µßDO…T_¿U„Ò¥9¹¢ier¦ä´w¶Ä“?Ôönóšqÿüò«Œì>Hú´í*ù3ÇÞ¹ý{O6ùÓ7ÉLÆê:×g’è¯ïýÛ¿!/6i#Ïßý„¼r»¨?¢ZE»võ•.­:ÈÈ oeÔîûöìMøÞÔÍë˜ÛsÞìu¥SÓg¤OÛ®2cø$Ù³cgÔ¹Ê6Ñ2bªxÜnÏy&¨œ¡tq0¡tì´yICiy$ÍŒPÚບÆ×é>aE²ªI÷Ç:Fm`Çê…Ùí±U0ïÌýúC/¦t›ÚWÜ,+æ|ð>?rÄrZê7ýO×z(ê ÏlÏŽ o«/þ¬ierª¸8¥5ü^lÒFŠ~/LøØKKÏYN;vJÙ¹;éurñâÞõËÛg÷n¼%’Ê9¶î#F„H÷œ§KÕµ–èœM<Îöø=ŸxÅ‘‘î¿oUç¼É_"Q›_¤rÎë]SCòg,Lzl7o„í´oø¸±‚e³ò’N#tò¸c}¸ ßöövËl¨ºÎÛíã®{õ­Që‡åMž›öï°Ã=a*á8ÝĪñŸî’mí_CÏ”œNøÇ€L ¥úîáåJ¼Ö—¦E85;‘ý{±][Y¥T_¿Ý†RóííFÉÞÿïúÆ&5?|µ=á‡.'îýk­¨?¾Ø‰Ýu7È÷Ln_CݾoÁ¥ßoÞJÛó—ìuLõïûôÉbéþXGÛãù™ÈͱÝJô:d–lÄú_›Öï7‘tC©ŸÇ6æ³S|ìXÊŸK0/bõèåºÉ_êm¹!Ö_m7>cZMAoù¿w§ô¼ªiÖÑÎjmÙ³gJdѤ9)­GîôuÌí9Ô©¯åmv}»Cº=šüß³›Çíöœg‚D¡T¥‰B©Ký¥‹ƒ¥—v¼wJGLÈ }(d•HÑm lßò¥?&.œ—’Ó§äà¾ý²í“-’;~fÂÖ'îx@VÌù@ Û'çΖHéù³R|ü˜ìþþGùhñJ×w¸í›{·Çv«ÉŸ#Æ_õ÷íÙ›ÖTO}#„¢ß åü¹3ròÄ Ù¹ý{Éyo‚íÐ}Õoú#YÕ¤mGdý²9vø°”–ž“#ʦÕëdÀó=Þî¹÷eî˜é)?î†×ß&#»’-k7ÉáÂB)=VΔœ–¿ü*–$ï½6@y(}ôÖ¦’Ýo¸l]ÿ™üºkœ*.–ÒÒsròÄqùé›ï$oòܤo„ÚÕT–æäÊ®ï~£EERZzNŠ“ßvÿ,Û·|)+ç.‰›¾žèg}²r­?r¤âœ¯Z›ôœ;åöZ›òîXY·dµ9xи¿ë–¬–›´Izìæÿª/3GL–]ßîSÅÅráÂy9U\,{Ü%ë–¬–1o¾g;½]Õ9oöº2wÌ4ùù‡Rrꤔ–ž“Ã……²~YôiÛ5áïiñÔù²÷Ç]Æ}/>vL¾ßúäfÏ´Ý]Ö­¦¯#3†O’]ßî“'NÈùsgäÐBù8MZÏgN·®îÕ·Ê„þ#eÏŽŸäLÉi9SrZvÿ£Ì›“Ò›`7×¹›c»}Üz,Ò´ô§Í×½ªºüôÿÙ»ó÷(ª„íãÁÑ™ÑÆYžqž×y&à‚k³/²+  ¢†D¶È*( È¾(‚²(²o" €ÙÃ’dël´õ/Üï™.º“îNwW'Nø\W®î:µž:]uçÔ©£Çd%=C=f£'Á¥¶˜’ÇÍ'ô©Ã{(ûÖ-Øuùìy}1w¹ÇGÏ]EZP:ì•þ~ÝÄ6ðYóŸçOžQ½ßÕ.³ìÔ_Nè“ñ(õ—Ê·çÉž—«Ôc'5o‡!®<þü~[ Jk¸o³ë¾(Íõ&ÎßáˆÕ§ÙëújÑJ;qZ9YY*..ÔíÌL]8•ªMŸ¯+Ó¶„óšÉêoh(®[PòÏùgéüÉ3*È·›çª¿¿cþï6ÿl Ù£§i×ú-ºp*U9YYæõΙ”ãZ2íµ}¨a¹Ë ç=‘•e[ª ´KÝ—”zì¤r²²´zÞg–þahPZ™ËnóÏÿ}2k“.Ÿ=/{^®Š ó•yýºíÞ¯’¦«åßëVø¹õÖ =µoóNÝÌÈPA¾]NŸÕ’iŸõòË€Õ(©¯ úè­zªý¿›Ê«Ô_NÈ0úq×÷Ë5ýÓ“š1,Y?ìܧ«.Êž—«‚|»Ò¯^S걓ڷy§VÌZ¤×ž*ÛKòìñSʼ~]çNœÑ–/6hÊ wƒ:ý³ºÏGw¢Üìl]»tY?íûAK§ÏÓÀç{ø]G­n·•} <¥%a©… téU,(]ý× ´$$õ”þwe£=(vSÆš?hÛVöõBÁŸL :r¾$åàá€ËºŽQYQÿø@øøóÖ{ÀÃo(T¦F¬c­³aÙê°¯¢CX‚Òÿ†¥¥ƒRgXê1(ýoXZ¡Aé‚Ï×”ÎY²2$Aé4‚Òª©F¬ö}»Ã¼ þtæ‚ð¯`7yˆFƒÚ÷6ÇÖ ´ÞO{{¼yÎl_»)ìÛ‚Ð#(…¿ø €ÊãúTC0/á‚áÌçB”:ÃÒ@‚Ò»ai¥s—dPºœ 4‚µø›MN¥ýø#PÕp“‡j¯F¬¦§øÖ]5ôå~Z1k‘9®ê¶5ß4¯ï$›cêž;qZÏýå™ðoBŽ þâ7ÕY³šO»½h)å½ ð¤ómuõüE­úx™¦½=^‰q úr?MI«ï·ìr¯³Áï ûú":ø”.*(5ÃR‚R‚ÒHöÂÿkäöVêøÖ]þN@°¸ÉCuç:–¥«£û4Þ´ë—Ïž¯1ÜP5”Â_ü†¢:‹oÝÕ¯qE=9²÷@Ø×‘g\ïáåÖ­k—.ëõ§Û…}]=¢.(- IýJ?ùt A)d‹‰UÛ‡*åàam^µ!ìëXÁMª»ž_Ñ™”ã²çæÈž—«S?ÿ¢FLöø2¹òl_»I?íûA­ÿ§~Ø· ‡ þâ7ÕA)*Û«uÚhñ”utÿ!ó¯E…ùº‘–¦ƒÛ¿ÓŒaÉý“…Ê Ja©¿A©3,¨ tÖ¢~¥K J#TÃ?<^)o:T Íj>TÀ òxJ—–”:ÃR‚Ò ƒÒé/&(ª€ÒA©3,È tùW›«LPúá‚ÀƒÒ©s†½BÑh꜅¥.¨:Aéò¯6”°† ” ˆz¥•”Μ·Œ ¨¢ü J”.]³©r‚ÒÅ¥@$ YPº¸r‚RgXJP dJ J?^FP T7”:ÃÒ*”.ZµÁcP:ÅW•”þwç”áã”þ7,­¬ Ô––JKÂÒJ J×”Q¬ê¥ë«QPºð3‚R ‚”.ü,ºƒÒ–¬"(ª‰ŠJ?Z²ªš¥ËW”–„¤¥@UhPê KJÿ–†-(]ò%A)Ï"!(5ÃR‚R ” ˆz¥•”–„¤¥]`  IDAT@US^Pê K£.(WAéûs—”Uˆ· ´$,­˜ tA)A)P•””Q/JƒÒ!Jg/ú<è tA)VΠtš… Ô KC”n$(P9J«RP:{AØ+¦Î^@PJP D7‚R‚R ê””Q ” ˆz¥¥@Ô#(%(¢^µ J—­ù¶bƒÒ¥_”ÕH…¥K¿¨Ð tÙšo J„A)A)õJ J€¨GPJP D=‚R‚R ê””Q ” ˆz¥¥@Ô#(%(¢A)A)õJ J€¨GPZáAér‚R Š ,(]NPJP T?¥¥@Ô#(%(¢A)A)õJ J€¨GPJP D=‚R‚R ê””Q ” ˆz¥¥@Ô#(%(¢A)A)¼húç'½ªï#a_?Àª&<ᵎ7øýca_? *éÙø-Hž­¹cg„}]PõÍ=M ’g«O³×þ.ðA)A)e]Ò±Ÿ®ÿš¦´+¿jPû^aßæÊv;3S†áЬÄ)a_+:Ön©Õó>Ó‘ï*¾M·°¯@E#(%(…U5(ý凟d8’ö}„ȉAé‰#)2 ‡~ùá§°¯Ke©îAi¤´kÕ)(õ¶ÏCY×Ò¯\5Ë^ë=ÜkýøìÃ…æ1óG»‡›x]~°á••íÝmˆömÞ© §ÏêfF†Š‹ ”“u['JÑÂIsÔúêû,oµ]kþà³údü:q$Ey9Ù²çåê©T­œ³Ôç¾²ÅĪý¿›ê½IÚ°lµŽ:ªÌôtäÛuçN‘r²²t)õœv­ßR¦®•lPÚä'ôÞ€$íùz»Ò¯\UA¾]ùö<¥_½¦#{hÉÔ¹nû/Tmj(~K­kçNœöXŸ¯]ºÐ>Ò±Ÿv|õ­®]º¬|{ž 캑–¦Ôc'µmÍ&%Æ%TØ9̲= 6(íR÷%­œ³T'JQö­[*..TÖÍ›ºpú¬6}¾NÃ;0§mñ7›$ÏVÊÁ#º™‘¡¢Â|]8•ªÙ£§©ý¿›jòպuã†òíyú~Ë.½Z§×寷îª]¶*3=]ÅEÊLO׎¯¾5ÿáæéz­í¿ùýO8€HAPJPêAix‚ÒŽ´ÔµK—˽Á«JAé;÷y\ÇââBŸ/Hžöu¶ÅĪýÿ53×iÓçë¼N׬æÓ*.*a8ôÕ¢•a_o[L¬êßûˆr²²dmX¶Úã4Mÿô¤¹Þ ÞóŸW… tàó=´÷›r8Š5 mw·ïœA©/i—¯¨Ó£­<λÅ_múiß^ËäÛ}žóïö¦Â»×òGöð„;(µºÝk|îs}3®¥©ó“Ï{,kµ]‹oÝU732¼–ËÉÊR|›nåî+_.¥ž+w”jßK×Ò|.»¸¸PÍj>m– E›ªß’p¥k®,w½=µO¡8Ç‚]¶'¥Mÿü¤¾þtm¹Ë_>c¾YÆõŸfþÔ—Ìë×Õö¡†e–íÚ×—Ò×kŸ}°Py9Ùúbîr½òxk¿1@UFPJPêAiå¥ï¯£K©çÌåضWÉýG)1.A‹&¤ë¿Þ½Ù®ŠA黾W†ߺ«®^¸(Ãp¨°À®÷‡NT†ôý–]2 ‡òíyjþà³a_o[L¬Ù«*óúu¯½²ãß­««Îc‡»6l•a8tõÂEß»žc½›¾æ÷|Ô6¾¿ŽÞT&hY1k±Ût®AiúÕkZ8iŽã”Ü”nÿÎ-ø*ýÈmÝ{jéðžæ4GöPrü%Æ ÖòóeÏÍ‘a8äp+¾u×2ë8ðùúí·;2 ‡r³³µdê\%Æ%hÒÀ$¥8dÎ÷‡ûÊÔ§¶ÿj¤×Ÿn§×Ÿn§¯Ý cºÕïd~îªþ½xÝW†WV·Û«¯¿¥ÅS>Öè®o«o‹8õjÒY#ߤï6í¸Û..Û.Ym׺Öë({^® Ã!{^®Nš£ø6Ý4¤c?­˜µÈ ƒngfz €ºÔ}Éœÿ¹§µrÎR%Çш×*¡C%Æ%hîØš9ü½r÷c AéÛ/õu «Žýø³æŽ¡Q]k䃔?FŸÎ\PæŸVÛÔPþ–Z×:=ÚÊ­;ÏIƒÒá˜Ë;õó/š40IÚvW¯&5øÅ75cX²¶­ùF‰qƒË”µzŽYY¶'¥ ÿð¸ù䂳}Y¿ä Mì?ZÃ;л=‡éÑ“µ}í&õou÷u JÇözGqÏvÐ’iŸÜ=׿;¨>Í^׸ÞÃU_òž¥Óç¹-{bÿÑæôY7oÞmSãÇhï7;Ì6ÏÓõÚù“gÌï~ûíŽömÞ©Aí{U‰'/‚EPJPêAi女§˜Ë\2í“2ß7yà óæ·*¥kÞíméÜ–+ç.˜Ÿµ{¸±¹}o¿Ô7ìëm‹‰u»¡ìÕäUÓl^µÁ GÂ5Ö'“ßJ2×½ýÿ5+óý§3˜7¾å=R쪲ƒÒöÿnªeïÏWÖÍ›néÏßÿ¨Ñ݆¨Á}ºMï J/¥žS“ž(3¿å3æ›ó(PŒë=Üüε¾:ÅÙ^T^N¶9ÿº÷Ô2¿«{O-]>{^†áPöí[e{OÖˆuë 6¶×;^·¹²Ç(µ²ÝþØòÅsþ¥íµÔ®Õ¸{¼ofdèåÇÊöXúr?sþ 'Í)ó½kPêë˜ø# ô¹¿\h~î:þ¡¯ñC7,[mÖ}o/9©Ì Ôêv{ÓüÁgÕâo6Õû]muz´•Y6¹ÿ(s«íš³WtQa¾:=ÚJínâ‘sŸ–é=® ÔÞæåd«Áï h9VÚÔPÿ–TvP:âµníÂðÎîál‹ î Õ²ü JãÛt3—ûñ»ï´ oA©s“OÆ`~6sø{f€îülÕÇËÌò/ü¿F—è[ï;>ÒRŸ}¸Ðí);wŠ´sÝf¯OnT%¥¥”Z J·­þÚ-råi›º7¸Û³qîØ^ç[ÑÛÝù‰¶^×ÛÛ±¬*Ai ûÜiAòlsº.u_rûnûÚM2 ‡2ÓÓz|½¢÷¹“sè€Û™™n7ôãßaî_!±'”Þ¹S$Ã(Ïn×ú-ø|€Êû”Î7Ó܇Ýêw’-¦d¬Kçg3ÞIö¹ 狲voÜf~¶çëí2Œ’Çî}•9|’×úäT™A©ÕívjVó)Í;C§3Ç u†“WÎ]¸”ºœÛVÛµ]ë·x=7¼)]ßÔ:_àth÷þ€—c¥M õoIe¥¶˜»¹SúÕkútæŸol/-Øs,Ëvò7(4ðî£íýZv hVƒRçÃE…ù^Ç 4(uj|Mì—¨S?ÿb–ß÷펀÷#@e#(%(õˆ ´rƒÒþ­î>búÞ€$¯ó%( Ý>wzåñÖæt®ß·ø›ME…ù2Œ²/ ÷>wêÓìusÚž_)³/ï9ðúTVPê¬ÇúŽ (Èð'(uSÏùâ×slbÿÑ>—ál¿\÷ŸóeHiW~õYÖµýr}éŠ«Ê J­n·-&Vþóœ[ê‹ë¹mµ]s}¹¿Ú=ÜØmá Jóíy2 ‡v®Ûðr¬´©¡þ- GPj‹‰Õ[/ôÔÁûÜŽío¿ÝÑÞov¨k½Žå–·rŽY]¶“¿AéìÑÓÌåøvÄ«A©³]»þkš×e”¶ýW#ÍŸ8Ëíåa¥ ””z4¡ïHóÂ6Îö¢Çi|Ýh]»tY†áЮ [=–õuámuÙ¡PÙc”ºöúš9|’×é"eŒÒp¥V¤<\ryåªÙ«ÆŠ†C¯=õBØ×Ñ“º÷ÔÒ­7dÍŸ8K¶˜’y8yôU—¼©è tð‹oêÀ¶½nãØÝÎÌÔ²÷çû5Ž?Aé#&›óvöêt?Ç|¿áÜWÒœ¬Û>ËVå¥Ál·-Æ=°üúÓµêÕäU=÷—gÔà¾GÕæŸ 4ºÛA©Õv͹ÏÓ._ º¾…+(ÍLO—a8ôÃÎ}/ÇJ›êß’p¥NŸh«%S纽,¨¸¨@ãß᳜ÕsÌʲü J§ zלÿ›Íßh­¥wÛµ,¯Ë4(íóÜÚúåF˜åìy¹Z·xeÙ—àTA¥¥¹ŽÍ8¨}oÓøºÑ:{ü” ᔃG<–õuámuÙ¡PÙAésyÆìi·iÅ:¯ÓEJPÚîáÆJŒKЈ×ßr›¶ª¥ÎGÕ ãn/@çË‚é•Y™œã3:ßdÜç¹»7Î/Æ6x~•õ2§ÎO>¯µ >—=7Ç\_‡£X{¾Þ®Aízz} ÔŸ Ôùöy×qB]ÇêܰôK¯e_Œmn®·1JÛÿ»i¹Ëv8нŽQê:ÜCÓ?þvíWë´1Ë—×KÔêv·}¨¡[HZ^Y×sÛj»öÙ%ûü·ßîx?±<á Jî?$Ã(ª¡þ½´+mj¨K©kžlýrcIØ]NOìrÕ(¹6ȼ~]†Qò¨¸¯öÍê9feÙNþ¥o½ÐÓ\×ò¦-Í[P:¨]O%Æ%¸=Má)(um×:Önéqþ¥ï¯£‰ýGëôÑcæ´†QòÏÇ9c¦< @8””zäzséÚ#Á•¯­Ý·™7” ÿðx™ï}]x[]v(„ã­÷)È0ÊÍÎözS)A©7U5(môÇ:ʾUòÖáoW®wç/1npØ×Ï—¡/÷s “œã–:ƒÓ@UVPêÔâ¯6Í5Õì…îtáôY½?tb™<•”6ðY³ž¥<ìöóü¹™©¦òžÌ›ð¡ÇÔ¸¶Y%M÷X¶YͧͷW{û'‘-æn`a½üXë€÷ÙóÿÛÈ,ïÏË_¬l·kBo!Ž· Ôc­]Ô¾—9ߥÓçU¿Â”ºŽ“ûþЉ-Çj›Êß’@ëZik–¼I¾°ÀnéÅHN®ç¡¯àÖê9feÙNþ¥ ÿð¸òr²KåËW v½¥¾ö‰kP:¨}o³üâ)—»Ý¥¯×:Ö.yq“ó÷ÓéèþCJŒ\ac{T$‚R‚Rêßûˆy‘ŸvùŠš?øl™i|Ýh¹>~êéñ?_ÞV— áJ“z 5—¹ën5¾¿ìã‚¥çóÙKÌÞBû6ï”a”ŒÛho°Êæz“=uð8³7÷¬QSƒš_e¥Nõ~W[#^Ë|[¸Séña}¥þXGû¾Ýa–ÓÝýÜ}·ç0ó» ËV—éµÚ½A'³‡ëÅ3gÝ‚º÷ÔÒÅ3%û&'+KqÏvp+[÷žZÚòÅsþI=†zÝVg¸mÍ3=ðýU#Ö\Oz<[Ùî–¯k“°ë=}}¥–Úµ±:òŒ £¤wp0~‡+(mù÷ºæP<®m‹±Þ¦†ô·$ÀºVÚ¬QSÍuñçEE/Õjá5̷Ÿ‡ç¾ÂÊ`αP-ÛÉß Ô«%Sçšó>²÷€žÿ_ÿzP[ JëÞSËló‹ ó=>ÅãëzÍy~:ËoZ±NÝt ¸žT%¥¥^¹Žñu)õœfŸ¤áht×·õáÈɺ‘–æõF«Õ?ê™=«ŽbmX¶ZcºÑðÎ4±ÿhm^µÁë…·Õe‡B8‚R[Xض×\îÕ õÉø4ºÛ½Ûs˜æŒ™nŽ{GPzk·t{ÑPÐ!Vl[ó ÃaÞð†C/ÕjԼ”ºêR÷%m\¾F…ö2cö9ƒÒÌôtÍ=M£º Vb\‚æOœ¥_/^2·ÿû-»Ê†z5bõã®ïÍiRÖ´·Çkl¯w´ê£e*È·›m–§P'¾M7ó1v{nŽVÌZ¤w{ÓûC'êÄás¾·çuè[LIÏSç›ãŽb­]¸Rû%*©ÇP}”4]'JQç'}‹ëìµo%/ý×g¸f KÖºÅ+Ëž‹·{ÿÖ=nÁÛØ^ï¨o‹8õnúš>ßC3ÞIö”Zm×z6~Å|©ša8tìÇŸ5wÜL½Ûs˜Æt¢éC&hÝâ•:²×sˆ® Ô«Ñ݆¸Å›zì¤OùXãß¡Ñ݆hÒÀ$->O?ÿ£Û8È–ÛÔÿ–T×J‰³½h–½uã†æŒ™®ñoŽÐ‚äÙJ9x¸L=ß´bì¹9Ú¼jƒ’ãÇ(¾M7õjÒY úhÞ„Í𱸸ÐgÌ9ªe;”6ýÓ“fÛfåÛó´yÕ½?t¢Fw¢ñoŽÐÌá“´yÕ}ùɧf9«A©-&VýZv1ûŽbm[ýµ&ö­Q]kÒÀ$ó÷ÅÓõÚ’©s•™ž®ɳÕö¡†–Î/€ª‚ ” Ô«Æ÷×1߈ꋷ­a¯ôwÌßOA©Õe[– 4¦äæîû-»Â¶ÝÁ¨.A©-&VÛ×n2÷qnv¶ÇÞÌUÑè®o»×ÃÁת”:µþŸúeG×0Á›}›wªYͧ<γùƒÏêÈ^ïmK¾=O£ºxnaL÷!f°èÉ¡ÝûË à‰k¯{OÊò¡{ƒN^×ã܉3!Ýîöÿnjö¦-§sÛj»Ö·Eœ2®¥ù,[\\¨÷=Z¦l8ƒR[L¬ã—y,Ù×È¡hSCù[h]+͵§uyõÜŸzöÛow4}È„Ÿc¡\¶-&° ÔSÒ Ù5”öæRê9³L(‚R[L¬F¼6Ð|2Á—Ò×k-þjSƒß?f鼨jJ J}ªï#zèD¥<¬ìÛ·tçN‘ìy¹J¿rUG¾;¨U/óùÔמzAß|ö•Ò._Qa]ÅEʾ}KgŸÒöµ›4gÌt¯÷V—mE¸‚R§¯ ÔîÛ”q-MÅÅ…*,°ëFZšŽî?¤U/SB‡>a¯NÕ)(íÙøó¸—~ä»*kúç'UXp7Ș=zZÐóªJA©' ú苹Ëutÿ!e\K+iWŠ •q-M»6lÕ;¯Æ—;º÷ÔÒ„¾#uxÏeߺ¥Â».Ÿ=¯/æ.W‡ÿÝHKSqQòíyúõâ%íùz»¦W%ƒR[LÉ –fO¶íUƵ4替e?ÿ£Nšã6Žf(ÛÔPý–Z×\5øýcš;v†Î8­|{žòíy:{ü”>Ÿ½¤ÌK‘^~¬µ>Jš®C»÷ëRê9åfg«¸¸P9Y·uúè1­™¿B]ê¾T!çX¨—hPêÔ§ÙëújÑJ;qZ9YY*..ÔíÌL]8•ªMŸ¯sÛç¡ Jm1±jû¯FZöþ|¥þrB¹ÙÙºs§H¹ÙÙºp*U;×mÖ¬QSÕæŸ ,C‘€ ” „;(Â¥ª¥@¸”":” ¼J JáA)¢A)àA)AP ™J JákPšÜ”š?ø¬Ox‘¦YͧÊÔíK©çJJ‚R€ÈDPJP \ƒROèeŠêÀÙ{Ô‚RÀA)AP ™J JáA)¢A)à?‚R‚  2””Q ” ˆz¥¥@Ô#(%(¢A)A)õJ J€¨GPJP D=‚R‚R ê””Q ” ˆz¥¥@Ô#(%(¢A)A)õJ J€¨GPJP D=‚R‚R ê””Q ” ˆz¥¥@Ô#(%(¢A)A)õJ J€¨GPJP D=‚R‚R ê””Q ” ˆz¥¥@Ô#(%(¢A)A)õJ J€¨GPJP D=‚R‚R ê””Q ” ˆz¥¥@Ô#(%(¢A)A)õJ J€¨GPJP D=‚R‚R ê””Q ” ˆz¥¥@Ô#(%(¢A)A)õJ J€¨GPJP D=‚R‚R ê””Q ” ˆz¥¥@Ô#(%(¢A)A)õJ J€¨GPJP õ­k IDATD=‚R‚R ê””ÂE§G[iÍü:òÝAõkÙ%ìëSYÎ8-Ãp”qíÒå°¯›Uk·ÔêyŸéÈwߦ[Ø×'RL~+IÛ×nÒÖ/7†}]B…zœ) cµã«oõíÊõaßÎÊ’—à±®†CúŽ ûúYUÏïHç˜?hת–h½FD‚R‚R¸Ò©Ÿy3œÐ¡OØ×§²Tç)¡Cs{†têöõ‰¿üð“ áGR¾.¡B=Ή#)2 ‡~ùá§°oge©îAiu<¿#Y4žcþ ]«Z¢õ}J Jᢺ\v«ßIãú ×[/ôôkúמzA=v2ý¸ë{¤(WƒêypªC Ðêõ”Сf%NQý{)wúµ¹Õ•Ñ]ß&( ïp«çXE ]«ZªË52å!(%(…‹êpXÿÞGÌmXöþü æ±ã«o ¢\uRl1ÔsU‡@añ”ÍýÓèu.ÿúÓíJ#ˆÕã]ÙªÃ9Vhת–êp €?J Já¢:\”º#( NuRl1ÔsU‡@ Ô]u?¿ J«Úµª¥:\#à‚R‚R¸¨¥îJƒS݃[ õÜ_Õ!P (uWÝÏo‚Òêv­j©×Èøƒ ” .ªÃE A©;‚ÒàT÷ ÅC=÷WuJÝU÷ó› ´z ]«ZªÃ52þ (%(… ׋Àɳµå‹ ºþkšŠ‹ ”™ž®]¶*¾M·rçÓ±vK­ž÷™®œ» Â»ngfêàŽ}×{¸l5|—­{O-Mè;R‡vïWÖÍ›*È·ëòÙóZõñ2½ÛÜc™¦~Ò\o¬_ò…Ïu6@ v»[ý£žÖ.\©ã‡Ž*íòååd«¨0_×MÓÎu›5øÅ7Ë]v|ë®Úµa«2ÓÓÍãµã«oµhòG~ÝhÅ·é¦m«¿6÷­7´ëî6Äçº7¸ïQ hÛ] 'ÍÑþ­»u)õœr³³uçN‘ òíº™‘¡”‡”78ìõ»´f5ŸÒ‚äÙ:{ü”ìy¹²çåêLÊqÍ›ð¡R,7H ôx_>{^†áЧ3ýkëòr²eé>Äü,¡C->Oû·îÑÅ3gu;3SÅEʾuK?íûA暴xܯùGc=†3PH=vR³GOÓ‰Ã)²çæÈž›£³ÇOiAòl5«ù”ÏyÓ®YÝçŸ}¸0 v±ÝÃM¼.?Ø ÔÊvî6Dû6ïÔ…Ógu3#CÅEÊɺ­“?¥há¤9jý?õ+ôünþà³údü:q$Ey9Ù²çåê©T­œ³Ôç¾²ÅĪý¿›ê½IÚ°lµŽ:ªÌôtäÛuçN‘r²²t)õœv­ß¢z¿«²zªãmå÷;RÏ1«uÍêñŽ´víê…‹2 ‡2ÓӽοáWa]†áÐÖ/7†l½“ãǘû¤óm=NãÏ?B†tì§_}«k—.+ßž§Â»n¤¥)õØIm[³I‰q eË„è€ªŽ ” .\/}Y2í¯óx·ç0óâØ“#{蹿<ã±l‹¿ÚôÓ¾¼–-È·—w¥ÊU… ÔÊv·}¨a¹ë¼rÎR¯Ëví=ä‹§­F¬£M+Öù,·sÝf5¸ïQŸûªòÝA†C—¯)wýý±Ž9¯~-»˜Ÿ;on}9~èh¹¡B´Õs+üÙçi—¯¨Ó£­<–¶]³ºÏÔZÝîµ >÷¹¾×ÒÔùÉç+äüŽoÝU732¼–ËÉÊòˆ¸î+_.¥ž i= Åñ¶r~Gò9f¥®Y=Þ‘Ø®}1w¹9ÍëO·ó8ÿþ­ºÜfø#AéÚ…+ËÝvO¿E¡¸F ””Â…ëEào¿ÝÑž¯·+9~Œã´pÒeݼi~ŸÜT™òŸï¡ß~»#Ãp(7;[K¦ÎUb\‚& LRÊCfÙvî+Ó3¥î=µtxÏ·²’eÖòóeÏÍ‘a8äp+¾u×2e_º^ºâl/šóX¿ä ósW/ü¿F>÷C ’•ívZ¿d•¦½=^ƒÚ÷V¯&Õ¿UW}”4]·33ïÞ(u,{£4±ÿhóû¬›7µpÒ%Æ%(9~Œö~³Ã\/o7Z[¾Ø`~ÿó÷?jt·!êÛ"Nû%*õ—æw‹§|ìq½woÜ&Ãp¨°À®mk6iöèiJê1Tƒ_|SÃ^é¯äþ£ôå'ŸúÕk®²4¾¿Ž.¥ž3·íÀ¶½Jî?J‰q Z4ù#]ÿ5ÍüÎÓV°ÇÛ¹¯÷mÞYî:vøÏsæ|:Öni~î¼¹½‘–¦’¦+©ÇP|c>1YgŸ2ˬž÷Y¹Ëˆ¦zn…k ~õÚÝe÷¥ƒÛ¿s BJ?æl¥]³ºÏÛþ«‘Ùæ}µèn0Э~'íbý{ñº J­n·-&V#^K‹§|¬Ñ]ßVßqêÕ¤³F¾1HßmÚq÷ü<\öü´z~w­×Qö¼\†Cö¼\-œ4GñmºiHÇ~Z1k‘Š‹ eÝÎÌTÛ‡–)ߥîKæüÏ8­•s–*9~ŒF¼6P ú(1.AsÇÎÐÌáï…´žZ=Þ¡8¿#ñ³R׬ïHm×\‡ðVçOœeNóüÿú¾æ „Õ txçfùS?ÿ¢I“4 mwõjÒYƒ_|S3†%kÛšo<>cõ€HAPJP ®ÉñcÊ|ÿblse^¿nÞ$º^<×½§–ùhqöí[e{_ÔˆÕן®5ç?¶×;nßë=Üüní•e–g{Ñ|ùRê9Õ½§–Çm¨ì1J­nwy^ºŠ‹ de_kôÇ:fÀt#-Mþó\™òï Hòz£5ôå»Ç{ŬEen~üþ1¥vŽåºzÞg2 ‡6,ýÒm¾åÝܺZå‘ õ<ü 掛i.¿[ýN²ÅXo×BµÏm1•”†ª=oVó)Í;C§3Ç u†“WÎ]¸[Ï]µz~ïZ¿%àv±toºH JCYׂ®sÌJ]³z¼#µ]sªï#æcæû·îvûnAòlFI¯Mo½ºƒŠ—99ÿ!â”~õš>¹ÀãÐ ®¬\#IJ JᯋÀ˜Xóq¬Ã{îövs¾L!íʯ>—áz‘Û¿UÉ‹\ߎ:±ÿhŸåÓ¯^+³lW•”ZÙn§OÆà× yéɹì뿦y]®·-מ‡þZ¿dU™ùGZPêZ×Þäu:o7ZVŽwƒû5ÇáÔ¾·l1±ºpú¬Žbó¦yư’›ýï·ì’a84gÌt·ù–wsÛù‰¶>o꣭ž‡‚?‚ëX‚¡j×B±Ï*3( E{Þá?ϹT¾¸Ös«ç÷¡ÝûnÛ=ÜØm‘”†²®#\瘕ºfõxGj»æj圥2Œ’Æ®/6sž_{¾ÞòºŠ Ô«·^詃;ö¹ßß~»£½ßìP×z=–±r @$!(%(… /s³K^Œà©÷SNÖmŸË(¯Giyo®ª=JƒÙn[Œ{`™q-MúŽT»‡«ÁïS³šO©ó“Ï›/E( Ý]v–×åz»ÑrÝçû%]g"-(u¯k“¼NW^Ò`·süÄ)ƒÞUœíE†C‡vï×[/ô4ÿ¶ÅÄš/e*ýøp¥‘ZÏCÁŸ@დCÞ®YÝç®ÂÕ£4ØöÜ5°üúÓµêÕäU=÷—gÔà¾GÕæŸ 4ºÛõ-`åÚ› }GšËt}¢+‚Rsžh«%Sçêê…‹æ|‹‹ 4þÍe¦µr @$!(%(… ._ŒmnNóÙžÇÓkÿï¦^—á|s®ÃQìqŒÒÒ{]¶·qÆjÄê·ßîøž¦[¿ÜXr³\Nï«Ûm‹‰ÕÚŸ›Ÿw¬ÝÒgÙÒ’ë²½•õ5F©sŸ{zS°¿"-(}î/ÏèÎ"†C›V¬ó:?c”s¼·¯Ý$ÃphùŒùæc÷ï HR½ßÕÖÍŒ ݹS¤çÿ·‘9~lûÿkæ6ßP¥ÑPÏCÁŸ@Á¹îÞÆ^¦]³ºÏ]9…5 ‡šþ9°7=Ûbbõj6fùòzîYÝî¶5t ®Ê+ëZÏ-Ÿß”ìóß~»ãuÜÈòT… 4ÐãʺŒpcVêšÕã©íZiÎp]8•*[Xs„ £dHæ>òº=òAæ>q>™QZ A©©Fɼà æ›Cá8Y¹F ’””Â…?®7`ƒÚ÷2?w½ ÿ(iºÇ²Íj>­ìÛ%oøN9xÄí;ç…ííÌLóå.¥Í›ða¹ȶ˜XådÝ–a8´yÕ† öÃW‹JÞŠZo/w«ÛíìÕgÏÍñº o’óå@†áÐâ)—»~¥o´R–a”ôhiý?õƒÚW‘”–l÷†C¹ÙÙeÆ,]}½õ>˜ãí<v|õ­Ò._QqQ¹ÎqIW}´Ì<.¥çÊ 4Zê¹Uåíóæ>k¶9){¬GÁ´kV÷¹«™Ãß3çõòc­ÞÏÿo#³üÇï¾_îôV¶Ûµ÷ê¬Ä)Ëú ¯¬œßƒÚ÷2ç»tú¼ êKUJ=Þ¡¬kÁ×9fµ®Y9Þ‘Ü®¹Þy€Ûu£³§ìw›*f|N×ýýÉøÍ^—a8Ìsì§}?”Y¯P¥ÑRÏ­òµÏý±Žö}»Ã\ö˜îCܾ·Ò®YÝ箆¾|·m/=î­_jÄšëéϸ{V¶»åßëšOìߺÇã‹n|…WVÎo[»ÃcܹSTî0žT… 4ÐãʺŒpcVëš•ãÉíš«z¿«m>¶~仃*È·Whݯï#æ‹ÿÒ._ñØkÕWPúR­^u[Œû?K J}]#IJ JáÂõ"pÛšMJî?JÃ;PrÿQÚ¶æó·;wŠÔç¹7Ê”oÓ͜ƞ›£³éÝžÃôþЉ:q8Åœ÷Áíß•½€¬q÷.g†ioר^ïhÕGËÌ‹o‡£XýZvñ¹®ã³]9Y7ÒÒ¼žß›V¬“=7G›WmPrüÅ·é¦^M:+¡CÍ›ð¡Âê¥Z-ÜÊZ½F R””Â…ëE 7y9ÙöJ¯óÓ}ˆycâÉ¡ÝûÕ¬æÓË6ðYÙ{ÀkÙ|{ž×ÀÎU‹¿ÙÜæ/í܉3åÎcÛšM^Ë'Æ•]+ÛýQÒt3DòÅS€d‹)饘—“]nyO7Z ÿð¸6,ý²Ü² ’g{\vD¥1%A‚óÍò¾x{tÏÊñvŽ–q-Mõï}Äí»ß}ßçMw(ƒÒhªçV8÷¹/û6ïôÚ{Ýj»feŸ»r}¿ÇÛU÷¼®‡§6ÕÊv·ÿwS³‡cy<Õs«çwßqʸ–æ³lqq¡Ü÷h™²U!( öx‡ª®EÒ9fµ®Y=Þ‘Ú®¹jðûÇ”~õšYnÍüZ·ß_G‡÷x?Þ¾ÎoŽõo¿ÝÑô!Ê” Å52‘€ ” .Úü³fž¦]ë·è©TådeéÎ"åfgëLÊq-™ö‰Ú>Ô°Üùt¬ÝRkæ¯ÐÕóUX`WÖÍ›úaç¾’›ˆrz&Ô½§–&ô©Ã{(ûÖ-Øuùìy}1w¹:üç¹€¶eŬE:òŒì¹9*..Ô´4íÞ¸M£»yŒÌ©á×ü‰³tþääÛeÏËU걓ú|ö’2ü‡b»{4zYë—¬R걓º™‘¡ââBeߺ¥ËgÏ+åàamZ±Nïèµ|Û5Ò²÷ç+õ—ÊÍÎ6Û…S©Ú¹n³fšêóÑú^ÖÚ…+uáTªY>ûÖ-?tT«>Zæõí²‘”:xm voܦŒki*..Ta]7ÒÒttÿ!­úx™Ï7Û{¼΢Éy¬·ÎÞl¥{tÚbB”F[=FB‡>úbîrÝH×ÒTX`Wqq¡2®¥i׆­zçÕørçaµ]³²Ï]½ój¼öoÝcî{{nŽÎ¤×òóýZ^Öw›vèvf¦Š‹ •™ž®}ßîиÞÃC¾ÝMÿô¤f KÖ;÷éê…‹²çåª ß®ô«×”zì¤ömÞ©³éµ§¼÷„µr~7yà Í–¬ƒ;öéFZšŠ‹ ”oÏÓ¯/iÏ×Û5uð¸*”{¼CU×"é³R×Bq¼#µ]så:.n·ú*¼n׿÷½?t¢RVöí[ºs§Hö¼\¥_¹ª#ßÔª—y —_~¬µ>Jš®C»÷ëRê9åfg«¸¸P9Y·uúè1­™¿B]ê¾äq™¡ºF ª#(%($çË}½ø D‚R‚RAÔ¾·9Öª¯^Ú 2””(OXMåVú•«fÙ‹gΆ}›ª€ ¡æ­=¯*’ûr««cº û:E2~¿+Ö+·Væõë^÷¥a84ôå~eÊSÏiϨÞJ JA¼Ýhµø«M=v2îúvÐ7ZÙ·o™eo¤¥UêöµúG=%tè£Y‰STÿÞG¾¿'«çØkO½àVþÇ]ßscåªzP:ãd·hò[Ia_§HÆïwÅJ9xÄÜö_}«Ä¸ÁÔ¾·Þ¤³ëòÙójû¯FeÊSÏiϨÞJ JAü½±~ýévAßh}2þ³ì¬QS+uûOùØ\v£?Ö ûþ¼±rŽÙbbµã«o¹±ŽrU=(}þ)íʯ2 ‡~½xI­þQ/ìëÉøý®8Ýêw2—½zÞg• E=§= z!(%(E©Œ-[L¬:Ön©—jµ¨ôí#(E¤ (…UU=(µÅĪÉO¨KÝ—Ôø~ÚãÊ:Þü~nêàqæ²ßx¦}Àå­ÖsÚsª‚R‚RD漄 ‚RD ‚RX A)*ÿxóû¸ùg™Ënúç'+}ÛiϨ^J JA¸Ñª‚RXEP]øý®žË¶ÅОPÝ””‹&<¡÷$iÏ×Û•~åª òíÊ·ç)ýê5Ù{@K¦ÎUëÿ©oN?øÅ7µå‹ ºrî‚òíyʾuK»7nÓÏ´WR¡:õó/**Ì×µK—5+qŠl5_<»Ìr;>ÒR×.].÷¢¿*Þh­]¸²Üõ^9gi™r¥ááZG|¹”z®LY+AéNýÊ]fqQÆöz§B¶»íC ƒª§¾ö_¤¥Á´kNïö¦Â»×rGöÐsyÆ­Ì›Íßð¹œÒŸe^¿®¶54ˇ¢Mµr¼OI)·ìñCGÕ¬æSË[mσmS­° …ûü¶žóûÎyQ IDATy¿ß‘”Ʒ^×#'+KñmºUØy¼#(%(E)o¿Ô×íæèØ?kîØÕe°F¾1HÉñcôéÌÚ°lµ[9çÖ»¾W†ߺ«®^¸(Ãp¨°À®÷‡NT†ôý–]2 ‡òíyjþà³fùÆ÷×Ñ¥ÔsærlÛ«äþ£”— E“?Òõ_ïÞø…úF«Ó£­ôúÓíL·ÐEÿðÎÌåúùM˜¤m»«W“Îü⛚1,YÛÖ|£Ä¸ÁeʶýW#s¹_-º{³Ö­~'·urªï#a¯#ÕA—º/¹ÝD®œ³TÉñc4âµJèÐG‰q š;v†f¯LÙP¥ÛV­I“4òAšÐw¤VÏûÌ<÷ òíjÿÍ*dÛ×/Y¥io× ö½Õ«IgõoÕU%M×íÌÌ»ëݱŸÏyDZPl»f‹‰ÕÀç{è·ßîÈ0ÊÍÎÖ’©s•— I“”rà9Ïvîsëi甎íõŽâží %Ó>1?;òÝAõiöºÆõ®‚ü’véôyfy«mªÕãí Jo¤¥é£¤éJê1T#ߤFLÖÙã§Ì²žÞ²mµ=·Ò¦ZѬæÓní­ëz”†ãüæ÷;z~¿Yv§G[…´ž—h{Þµ^GÙóreÙórµpÒÅ·é¦!ûiŬEf¾™éöÏ#P9J Já⹿ï>MX}ýéZuÉ5(mû¯F²ÅĪÞïj+'ëv™i×/Y%Ã(é¡éüÌj›jõx;ƒÒ_~ø©ÌwMxBÏœ5ƒŽÒo˶ڞ‡ªM Å9lPZÙç7¿ß%¢ñ÷Ûê²+uŸ×¸Û¶ÜÌÈÐ˵.3ÍЗïžG 'Í©Ô} J JáÆõf烓*ëéFkt×·ÍÞ3®Óæåd—¹ ?òŒ áô«×Ôà¾G=.£²^èÖºÅ%½9òr²Õ⯶ ÷?Ai婪Aiý{QÖÍ›f¯¬ÊÞ/?íûA†áÐÙã§|NIA©•vÍõXÎ5Õã4Íj>e3×PÑSPj‹‰Õ…S©2 ‡æŒ™n~öáÈÉeö‡Õ6Õêñö”Úbb5sø$sûz7}Íí;«íy¨ÚT«B”VäùÍïw‰hüýޤ 4¾uWsYcºñ:Ý‘ïÊ0:“r¼R÷% (%(…ç…i^N¶üþ±€ÊzºÑrŽƒuçN‘Û´ÎUÉñcd‹‰UË¿×5/œ×-^éuUõFkÄkÍå]8•ªá¨î=µ^.Ai婪A©-&V‡vï—a8tîÄ™ ß î{Tmjhö¤úvåú’ÀãÊUŸå")(µÒ®¹Žèk|Á ËV›ms¬RoA©sLÅOÆ`~6sø{fÐäüÌJ›Šã]^PÚ¯esû\KE{ª6ÕªP¥¶˜Š;¿ùý.¿ß‘”~:s á¢Â|uz´•Ú=ÜÄ#g›Z\\Xæ…Š b””Â…ó‡v︬•­î :™ésÇÎ𺌪z£e‹¹{ñï”~õš>¹ Ì›¬}!(­þ#(%(…‹£ûÉ0J3­ï#•õt£ÕîáÆJŒKЈ×ßr›¶ôÖsyFwîÉ0Ú´b×eø{£õj6æEÿÄþ£Þ[¿ÜXr!_N/²rÕˆÕÈ7)óúuFɘ\/Æ6÷:ý‚äÙæz7ýsøÞô ¬¥gŸ’a8”rðˆÇï«jPºvÁç2 ‡Žbu¬ÝÒã4Î7¸—·ì*sŽùÁJ»æ:Fiû7õ:s¿9ÅåŽQ:¨]O%Æ%¨ómÍÏü JýmSCq¼ƒ JCÝž» °Mµ*ÐzÎó›ßïÑøûm5(ýÿìÝ÷CgâpÌ¥\r1ùÞå.w—»CcK²vÄÞk‚EÅŠF *‚€•X‚X°7$F%QT4FÅ v± ‚d¾”eáùþ€3ìº}g–]Øç‡Ï/î¼3ï̼ó.óøîûÖå5ÿyEMŸúòe5úü»ƒÝÇ""""çcPÊ ”ô¬›·\úcyÙô…v•5õ¢eŽ©—úÔ”«J‹‹ÍÎGeë‹VïuÎcíœev_‡ÄÍ5«àVVhY@D?8³ô"†%‚ ÃÏz¸¼=4dr‚ÒS’!:hJKÐþÏ-Þow JÅQ?šÒ³ÛØ”Ê}Æön©yÆ*Ê•yÆ,‘Ó¯éßË5‘Ñ&·ñmÜ Å…Fá¹¹ Ô[ƒRsLõ©rï·£A©ÊKÙþÜÚ}q$رU¯Ö¶sKóoŠ\ù|óû»†'~Ë Jím篳§?ŸÒ/P:Ö¶è uzˆˆˆÈ6 J”’žnk’¢"‚ý?k”û¢9jºôÇóù£§Ðñ]ã?öm~±nä Mi A‡+§/Ø}VÍ^*ÕeB·áV·ؤ«´Š´)ú/–^´¦©}É^íòöÐÉ Jõfmꧦî”&¬‰—Ž=¦ÓP“ÛØ”*ùŒ‰sz:‹œ~­õMðø~A‡’¢"øÕßèó#¿$Iç9jºô™«ƒR¹÷[NP*·?WªO•­‘7ÊJŠ!¶-’äÊç›ßß5<ñû[öÏþílç–®¹Õþ¼‘7¦Ý‡ ÔLëàÈOý‰ˆˆÈ¹”2(¥×„ãåËjéÞô[iغd-æ›…ð€`,š‰mÑpýÜ% mÙG*'÷EKÕÈ’ÏHÇÍzôëç¯@x@0挞ÕÑÒl¶Œ@Gý BÍ¢;óÆ† fFömÝeµŽþªRÙ‚¼<¬ŽˆÆüq³°)*©)Wà×¢Áö‡v샦´‡’ žôñÃÔþc±aÁJiei­¶›t5{\߯­ )+… Ôü\6qó.,œ†ÈQÓ±&2i×RŽMŽ‘”vÿ¨4‚P§Ó")~7"F#ÄoN Çá„ÚàÌ‚Ò1†JÏvA^6EÅbÚ€qôùã»úcú H½pÙæcËyÆô¯þóçX²HzÆnœ¿ ¿½=wGû5•—7‚zH«ÅkJK°cÕÌ=˦/Ä+©Ò>SŽýU£Úr®JåÞo9A©Üþ\©>U ú«tŸÜ ƇJí|ßVÃ{ãêÅÚøýí™ßßJÌjO;½ýùèŽ_£ª²\*sëÒu¬›·sFÏ@ÄÈ`D/À¾­»põŒýA9ÉÇ ”A)™æ? ÅÒ±æèž’ý¢åUó¢qîÈI«ÇµåEkd»Á¨(ט,ÿàÎ}«åõG‰½.ÌšÁ¶âˆ3K^¾¬Ftð«ÇÕ­h˱É1r‚R•—7f|=Úª «÷Ý‚R•—7ÖDF)æØrl¹ÏXòžCuÚÎé×D#ƒÍž« ÔŒÂòmÜÊ Œ«ƒR¹÷[VPê%¯?W²O•kxëRf­»úùv´óû»~+”ÚÓÎM¶k;ûóñ]ý‘›­¶x½´ÚJ´{«™S®™Ç ”A)™Ñùƒ/±<ä\H>ƒÜl5ª*Ë¡)+ENf®Ÿ»„Í‹VÌåċ–hÖÐÉ8u ¹Ùjhµ•¨¬Ð O­Æó—‘°6Þì èëFu‚?Ga~>´ÚJäçäàìïÇ1oLˆÕ²íÞþ ëæÆàÁ{(×”¡\S†ŒÛw±36ÎhA‡!ŸõÀšÈh\>uOÒ ´¸Zm%JŠ qïÆ-ìÙ¸CZ Û3¿ Âù£§ñ"7Zm%4¥%¸Ÿz?ÅlDÿÿuvyÛhä¥*/o mÙ¿ý¼ê§™¨¬Ð@[UâÂdܾ‹c‰‡°:"Ú( s‡ eT‡!Ø—€ô[iR+.(ÀÓŒ‡HM¹‚C;öÙ<Ç¡œg¬ý;ŸcãÂUx˜våhÊJ‘~+Íä3¦{û5}ƒšvÞ;õð1*+4(zñOœ­i?Œ·w‡ TÎý–”ŠéÏ•îSå h;§$£ /¯¶>aÔÎÝáùv¤óû»~+”ÚÓÎMq¤?÷y¯9bfD!åøYä©ÕÐVU \S†gŸàôÁcX:mƒR"""`PÊ ”ˆˆˆˆˆˆˆˆÈã1(ePJDDDDDDDDäñ”2(%""""""""òx J”y<¥ J‰ˆˆˆˆˆˆˆˆ<ƒR¥DDDDDDDDDA)ƒR"""""""""Ç ”A)‘ÇcPÊ ”ˆˆˆˆˆˆˆˆÈã1(ePJDDDDDDDDäñ”2(%""""""""òx J”y<¥ J‰ˆˆˆˆˆˆˆˆ<ƒR¥DDDDDDDDDA)ƒR"""""""""Ç ”A)‘ÇcPÊ ”ˆˆˆˆˆˆˆˆÈã1(ePJDDDDDDDDäñ”2(%""""""""òx J”Éâ7 玜ċÜ\h«*ðü™7/^ÃŽU[ñ]ŸÑНý;Ÿãäþ#(+)FòžCh÷V3—_[š€çÏÔPg>Ô~.¯OCõõç=¿·.]GP.¯ñ~é«Ïßcæ,þ.Çáè¯<꼉ˆ¨aaPÊ ”ˆH–±qYi×R?fÔÄÙLjìòë`«œÌ,©Þïg¸¼> Uðà ÒužÚ¬ËëC¼ßDúêó÷˜97/^ƒ èpçªùïý†xÞDDÔ°0(ePJDè≳ÃMѸ.Ã,îgjÿ±Ò¶ù99XºSú"ÌVÍ^ŠS’‘°&^ñúÇÌŒ2¨çâï"í*ßý£6˜Ú,V…-AÛ7?­Ók_\X Õ;O­vy[¨/ÚƼ±!6PfpæYx¿=—+ûs9ä~¹#[‚Ò†xÞDDÔ°0(ePJDH© ôÌoÇ!:”kÊÐ￾uVÿÞÿêuæ3‚Ï?A÷ÚØU~ë’µÒ9vøóuzí×Ï_!{Õì¥.o õAÛ7?•®Yü²6•apæYx¿=—+ûs9ä~¹#[‚Ò†xÞDDÔ°0(ePJDȯEoúø!ÐÇc;“^2ü´Gú÷@?ø6niq?/rs!:œØw¸ÎÏÁç½æÞz :¾kÿ‹±«_¬5í†Mºº¼Ô J‰÷›Ìqu.‡œï1wdKPÚÏ›ˆˆ¥ J‰ÈÃé‡P[—¬µ½l#oètZ‚?¯Üìòó°G}~±öD J‰÷›Ìaî>l J‰ˆˆÜƒR¥Däá J ¯Ü_¬ë¥ÄûMæ°?w J‰ˆ¨!`PÊ ”ˆ<œ=Ai§÷[Ø4·©(̪bõ óŸjö8 ƇZ-ÿóÊÍvÕ½ï'>ŠÕýÁ{&‘ýä©]û 4Ç÷þŽì'OQ®)Ce…yj5Òo¥!yÏ!E¯·hjÿ±HXëç.!7[Šr ´UxþLã{Gð  Ëwÿ¨ 7ïÂíË7 ~š‰²’bTU–ãù35Nì;ŒiÆ)ÒÖöÇýbx­ô‚³S’‘v-Å…¨¬Ð '3 ‡vj€KŸ=gßï žHÞ}ÏŸ©¡­ª@A^Î=ð€`¨™/Œ³‡Oàѽ ¼ÈÍ…¶ª%E…H»–ŠÍ‹V£ÇßÛZƒâþƒOPôØr9ú|Ë=o¥úóAM»a÷†Ÿ‘ùà*+4(ÌÏGÊñ³˜7&Äâ3â(¹ßc½>n˜Q8ðÓܹšŠœÌ,hÊJQQ®AÖÃÇ8ðÓøÕß)í\äÛ¸%6EÅ"ãö]hÊJ¡)+ÅýÔÛØ°`%Òo¥™lkrÏ[¤DßBDDd ƒR¥Däá”Ö 4qó.«uÞµz›âíãÎÕT«Ç=óÛqtúK “å{}ÜÞ¡z+”šS]]…0ÿi.•¾ßþüíØg±ì‰}‡Ñî­f¦½i§Å²¹Ùjøµèm²ì·­úÚt¿ž¤?0Y¾Óû-pp{¢Õò?ÅŽ,våýöä ÔÑç[îy+ÑŸÏ=•³e®ž¹€Î|©èõ’û=fK;×VU`nàLÅïµÊ˃>í†ì'O­ÖÁA©Ü¾…ˆˆÈV J”‘‡³'(mýF|Ûª/¾mÕþªR¹ýq¿Hÿ®Ï·q+ÅêéÛ¸•Á¾Cü&Ùõ¢Õ럤²{·Ô†Pm›¬{Û7?U¬îƒ›u7Øwʱ? ¶¥úçz÷úM,š‰I½F"ÐÇÓŒCÌŒ($ïùÍ)!”æçä ffB‡MÁ¬¡“þ#2<’êuö÷ãfG`íKÀßÏÇ”~cè㇉ÝG`Md4 óókƒ×F¦ÚÛÖúü»ƒAyý@áÚÙ‹Xð€`„#qÓNh«* :”£×Çí]þ*y¿ü’$•¿~î‚1¾«?NCúÍ;VŸ÷Yß~‡­KÖ"|Ä÷ßÕ>~6:^„\1º o=PÚæÁ{صz¢‚"0kèdLí?aþS±nn –‡ü`T¶ý;Ÿãò©óRùÒâbìû '†#Äo挞•¡‹q,ñ&vá6÷Û“ƒRGŸo¹ç-·?ŸÜ{^¾¬–ÚDÜÒuóŸŠE“#‘zá²´¿‹'Î*:²Tî÷˜~;OÞ}‹&G"tØ,ŠÝ~†V[ AС¢\ƒ~ÿõUô>w|÷ ×3ìÕ¶nnŒTöê™ èùv6—uåýöô ÔkÏ·œóÖgoÞú&xšñ‚ CqañèèFÞ£š5:S¼FŽ¥¦Úù‰áÒ盢b­ëª°%Ò¾ã~\oô¹Ï{Í¥ ÕZ[säû[NßBDDd¥ J‰ÈÃ1(uÿ tßÖšSe%Åèúª:­«¥ Tååo Mi A‡Ô”+vïÿÚÙ‹2nßU´­Y Ú½Õ ¥ÅÅN­™Ôk¤T6tØ£Ï 3Ú½Õ Å…ž?S÷qK»êåÊûÍ ÔÔGî·ÿWý ÊØ"am¼Ñ~|·Äº¹1¸wã4e¥Ò¶Zm¥Á¼´QAFe 3M®ýiü„nÃí¾^®¼ßž”:ú|»*(=}ð¡æg÷–¶[²HÚïðÖr휔Šß/–þóÉ^#Û –Ž»nnŒÙí”QCÀ ”A)y8¥õ#(Uyyã»>£‘rü¬AÐõòe5Îüv#Ú rJ]m J˜d>äZ?…M+‚ÒäÝ­Û•ì½ßº ·;(Ý—`°þÿël†Z¢dPþ£TnØ—ýì¾V®¼ßž”Êy¾]”^9]3=…:ó™Í÷õõÅÔ⌠Ôí|b÷Òq˜iv;¥DDÔ0(ePJDŽAiý JE~Í{!né:d=z,‡¶ªóÇÍR¼®¶¥ëæ-—êÐv°ôïúÁ]n¶ Ƈ¢ï'ÑîíÏàÛ¸%üZôÆ¥“ç”*t¿G´$}¾pB˜CÇÒ_uþàöDú|ƒÎ|‰vo5CÏ´Cx@°S‚Ò%SæHåÆufw½]y¿Œ•ŽmjDµÊËr€”ýä)A‡“IGM–µÊ=¶rŸo9ç­ÏÑ¥%E…·«¯#JÑÎõû–å!‹ÌnÇ ”ˆˆ¥ J‰ÈÃÕ× ô›/zÖ†BÃí*»)*V*Ûéýº]E^å壿°iD“U¼:l òŸ?‡ èPUYŽÞ]­«-A©8—Ÿ èÐõ¯µ‹%nÚ AÐA§ÓbPÓn&ËŠ«K[|©oä—/«!:ü¼r³MõnHA©­÷Û·q+é§Ï‰›ÍÏ#hN¯Û„¤¦¶àÝÅ)Aéw}FKåV…-±»î®¼ß¡Ã¦HÇžÒoŒÉm,H·ïBtHM¹j²¬¥ÀPî±åû|Ë9o}ööçús”öûO'³Û‰u×é´N›£ÔÞï1WµóÎ|‰êê*‚‡vì3»­mÍ‘ïo¥DDTW”2(%"W_ƒÒ^ÿì ßÒœi¦,ùA*;ä³u^÷ÄÍ5«šWVhY”I?P°74¶ÆZPÚéý()*‚ Ô¬´®ÿ™8rVSZbvÿ6¥^Þ()*„ èp8!ɦz7È Ô†û-.XTRT„ok×~õGy™ +”¶çs”•Ô¬J¯~ši÷`¸ò~ëŸóúù+Lnc)@:u YzNÚ¿ó¹Åûýz`(÷د[0>×Ï]Bòîƒ:Ryɾ圷>{ûsýý®‰Œ6¹oãV(.,°ä*ÁÞï1W¶óÔ”«J‹‹ þCÌ‘¶æÈ÷7ƒR""ª+ J”‘‡«¯A©ª‘·¬\>uÞ®²Ó‡Ô¾l®Žˆ®óº¯š½T:¾- × lÒUZEÚ”)ý”>IŸ÷š}¾36N:öŠY‹ >KX/}6¦ÓP“û·5(M»VSüçÏáÛ¸¥Õz+(ø6n…û£´¸Oœµ;„´‡œû>â{é³Ô —Ñóíl>n·¿µ–Fîž?zªFÆÛ8+(Uyy#né:©ìÕ3Ðû_l.ëʩ훟J‹©Ÿf¢Ë‡_mc)@Òÿ‰·©Ÿ5[ å[ßXßo¥ã‚WÿH±¸½Üç[Îyë³·?oýF<¾Ÿ!ý‡‚ÿWý>?òK’´ÏÈQÓm/ìüse;5]:öù£§Ðñ]ãilåøþfPJDDu…A)ƒR"ò@~-z#ÐÇ>~Ûy˜ôòqà§=Ò¿úøY ¤\”zyãäþ#RNî?‚ãC3# û¶î¾­æzìÛ¸•´š·N§Eâæ]X8! ‘£¦cMd4Ò®¥Â¯E§ÕÛ_5@ªwA^VGDcþ¸Y؋Ԕ+FÇ>´c4¥%8œ„¨ õ @ ¦ö‹ VJA‰V[‰Mº*ZW1(„šyã—mÄœÑ3°dê\ƒù,ÝË0špL§¡RðV—‡MQ±˜6`}¾Áø®þ˜>dR/\¶é¥^ÂÇ÷3°äÞoý碤¨ûã°ø»H„ø^jgWN_Àìáӌʞ?zÚ ™8ã»úcL§¡˜Ü{bfF9-(íô—í­\S†Ã IX6}!‚1Ü,,Y„à Iøuýv§Þo{é·Ï'é°#?ëÑc¬Ÿ¿áÁ˜3zVGD#?'Ƕ ÔÎóVy1(%"¢ºÃ ”A)y ‹' WÒ6ÇÒ¢*î”o=PzA~݃;÷-–ÕÍdJ˜¿qˆ¤$ýKÖŽ-Ž~²äåËjD/P¼žúÁ•9Y›£pMd´¦Xbí¥¾ë_U‹Y»ßJ â0¢ô[iNkrïwûw>GÒ¶_­îcST¬QÙ~ÿédÓñAù TåU3ªUüI¶%OÒ8õ~Û«ã»_H«©[b.@šñõDh«*¬–7Ê=¶~ìéC•x¾åœ·>Gúóˆ‘Á¨(ט-sùÔyø6nå´ç\ÿ™±õ{ÌÕíÜ·q+œ;rRv[³÷¼Åíåô-DDD¶bPÊ ”ˆßrÎ[Ÿ#ýù ¦Ý°gãd=|ŒÊ Š^¼ÀÅgkÚ®“G’ê³õ{ÌÚ¹Ê˳†NÆ©ÉÈÍVC«­De…yj5nœ¿Œ„µñfëæèy«¼”QÝaPÊ ”ˆˆÈ,[V½÷mßü±á?¢²¢fZâ¦.¯)‹A)ƒR"""³”Ö † ÔüìÝY#x‰ˆˆˆˆÈu”2(%""2ËÓƒR߯­â7 É{~“~ö¹-zƒËëEDDDDDÊcPÊ ”ˆˆÈ,OJƒzŒRN‹¸¥ë\^'"""""r¥ J‰ˆˆÌòô Ô·qK£?^ûw>ÇÉýGPVRŒä=‡Ðî­f.¿¶ 4ÏŸ©¡Î|†)ý]^ž7¹‹å!?àìïÇq,ñËëBd Oí×<õ¼‰ˆÈ30(ePJD$ËÎØ8‚ά´k©Š3jâlƒcDŒ vùu°UNf–TïÇ÷3\^ž7¹‹;WS!:ܼxÍåu!²…§ökžzÞDDä”2(%"tñÄY‹á¦h\—a÷3µÿXiÛüœ¬ ]Œ)ýæ? «f/Å©ÉHX¯xýcfFÔsñw‘v•ïþQLí?«Â– í›ŸÖéµ/.,ê§V»¼-ð¼É]0(õ\mcÞØ§üÁ™<µ_óÔó&""ÏÀ ”A)y ¥‚Ò3¿‡ èP®)C¿ÿúÖYý{ÿ«Ô™Ï :<{üÝ?jcWù­KÖJçØáÏ_Ôéµ_?…tìU³—º¼-ð¼É]0(õLmßüTêâ—mty}ìá©ýš§ž7y¥ J‰Èùµè@?úøalçaÒ ÏŸöHÿèã߯--îçEn.A‡û×ù9ø¼×Ã[DÇwí:]”ª¼¼1¨i7 lÒÕåí€çMî„A©gªÏA©ÊËsû5O=o""jø”2(%"§ÿ’ºuÉZÛË6ò†N§… èðóÊÍ.?{¸:(%"c J=S}J‰ˆˆ¨aaPÊ ”ˆ<œ£Ai}~¹ePJä~”z¦úü]BDDD ƒR¥Däáì J;½ß¦¹MEaþS«g˜ÿT³ÇY0>ÔjùŸWn¶«î}?ñQ¬îîÜ3yŒì'OíÚOð  8¾÷wd?yŠrM*+4ÈS«‘~+ É{)z½m¹î¯{}a,¹ç=µÿX$¬Çõs—›­FE¹Úª <¦Æñ½¿#xЗ??–ôø{[lY¼·/ß@qa´ÚJ”"ëÑc\ý#;cã,ίÛåï°~þ Ü¹šŠ²’bhÊJñèn:v­Þf±}vÿ¨ 7ïÂíË7 ~š‰²’bTU–ãù35Nì;ŒiÆY¬w»·šaR¯‘ؼh5Î=…'éPZ\Œêê*T”kð"7©.#ÌšÙ}ø¼×?LŠÄéƒÇ“™…Šr Ê5eÈÉÊÆÕ3·tzü½­A1(Ug>ñÄCPg>CUe9Š póâ5,Y„voæ”{•“• AÐ!y÷A³mQl¿Áƒ Û]TP„ô™_ó^&Ëß¼x ‚ Ã«©Š[ áÁ8{øÝËÀ‹Ü\h«*PRTˆ´k©Ø¼hµÑ}Râ¼íý.Ù÷‹Éý·~£ ŒÅåSçQôâ*Ê5xšñ kã1À»‹SÚŠýÚ¶è 8ô4ßÏ@a~>´U(.(Àµ³±lúB´çs§Ôý9‘u J”‘‡cPZ?‚ÒÄÍ»¬Öy×êmŠ·{^¬Ûü©©¢ç-g–œùí8:ý¥…ËŸ£× û²Ÿ4‡¯%]>üÊdù #,–/)*BPÏ“e{}Ü^V[9¾÷w›îwä¨é&ËOéˆÜlµÅ²Zm%|·²û~§¦\qÊýöä 4qÓN‹×<7[ ¿½Ê¹:(íú*\;{Ñl™Šr ‚¿^uѯݾ|ÃêáŽ`NDDdƒR¥Däáì J[¿Ñß¶ê‹o[õ…¿j€ÁK¬øïú^BäðmÜÊ`ß!~“¤ãÛ”öúg©ìÞ-µ¡c@ÛÁ&ëþúh97ën°ï”cØõ‚©®w¯ßĢɑ˜Ôk$}ü0mÀ8Ä̈Bòžß,ŽðSêºëKÞó›T¯_×oWü¼ÅëüœÄÌŒBè°)˜5t2bÃDæƒGÒ±Ïþ~ªF®–ôÝ»qK wÆÆaú Ói(&vÈQÓ¿l#þ8tÜdÙmASV AÐASVŠÍ‹V#¨g‚MÀŽU[ ÕVBt(ÌÏG¯Û›ÜÇþ¸üøý|Lé7>~˜Ø}ÖDF£0?¿6t33‚ëÔd‚•$ï9„Øð9j:¦ ‡_ODÔÄÙøuýv“#ö¾8^ªŸ èpëÒu¬›ƒÙç!tØDE`ûòMHŠßmö~—c×êmXü]$f}û–M_ˆŒÛw¥}þ£üϳ=9(õíwغd-ÂG|ñ]ýèã‡ÐaSðÇ¡ãÒqï\1®·œó¶÷»¤Ï¿;•¿rú‚Tîê™ ˆ Š@˜ÿ4ü³šÒ‚:A=F(z½”ê×òÔj¬‰ŒFä¨é6+f-6hç»7ü¬ø½fNDDdƒR¥Däáêë¥ß¶êkWPªÏÕs”Š#öl}ÁLÚökMhVZâ6£mf|=/_VCt¸~îÚ½ÕLñó¶4geÇw¿^ÔA甑cŽê÷ŸNR½6EÅÚW¾Qíy¿ÈÍÅÏzm3}Èiÿ›­¶kÿß¶ê mUA‡£¿0¹”f>xd×¾;ð¥4 V[U¹3í*oé~wúK <ÍxAС¸ À¦öfOJ-9òK’tìo¾è©èy‹ù.™7&D*“¸y—Ñçþª(+)† èð$ýZ¿ÑÄi×HÉ~Íç½æx|?CúO’ŽïÖÍ÷ûs""¢Z J”‘‡cPêþAé¾­5#`ËJŠÑõÿT.o3ýþë‹â‚iTTïu°©œ’/Ö*¯š9@Å‘c©)W\~]D}þÝÁ¡gJåUó“{±lÄHóaÁÕ?R :ÜO½mwýÄŸ+gܾkòsGƒÒUaK¤º¯˜µØîzY»ß«#¢¥ýh3HÑ{Æ Ô´I½FJÇ6EÑó9ò]"î÷En.|Þknr›usc¤ýNí?Öi×Hé~myÈ"©Þc: uú=fNDDdˆA)ƒR"òp JÝ?(5t²TßGwÓâ7É©#¤,ió§¦RÐV]]e×ÏZ•~±Vyyã÷]û¥º(9Õƒ\÷SoCj~ú›°&Þæ9o·/ßAСª²ƒ›uGßO|LJŠß]3rS[i4—àëÚ½Õ ½>n/F¯YNf–Éí JÅ𶬤ءE—¬Ýï)ý͆vr1(­ÕåïÐõ¯*´ùSS nÖ]:vÔÄÙŠž·ÈÞï’Î| N A0¿È“Ê«&÷ûóÊÍN»^J÷kº —êíŒéTô±?'""2Æ ”A)y8¥î”ª¼j4QNV6¶/ßdôsXgÛ°`¥T‡ V:õ¼my±^ºXª¿j@ßKsüš÷BNf–T·êê*\H>ƒ9£gX Oî?bpŸmÑõ¯Æ£ŒÇu†ä=‡§VK¡’8Oœ§4'+Ûd JÅœ.Ÿ:ïÐ5³v¿õç²´÷™·Æ“ƒR߯-±nn îݸ%Í+†ðúsGFE(zÞ"{¿KF´$m33Êâ¶%EENHVüº‰”î×ô¿Û^§•ÆþœˆˆÈƒR¥Däá”Ö TååïúŒFÊñ³!ÙË—Õ8óÛqÅŠlÊèŽ_K õÜ8ÙêHF¹çmË‹õ“"¥k1¡Ûð:¿—–tùð+l]²ÖhõúÜl5bÃ4˜^>uÞî ´ï' ö±~þ ›Ê)”–kÊ :œØwØ¡ëeí~û5ïe6´“ËSƒÒþÿël†Zâ.AéÄîµÓS,œnÓ}½rú‚¢×MŸÒýš3Û¹>öçDDD¦1(ePJDŽAiý JE~Í{!né:d=z\;ú«ªóÇÍrZÛ¿ó9ܹA¨Y•|`“®N?o[^¬×Í[.]ƒ€¶ƒëü^Úzí‚qæ·ãÒBJ‚P³"|—¿2ØöôÁcÔO3:–þÏvs³ÕX0>}?éˆvo߯-á×¢7.<ç” 4?'‚ ÃÅgª»+¤ì'O!:œL:jòsKaå‚ñ¡VGÁY å[.ý`þàöDú|ƒÎ|‰vo5CÏ´Cx@°Ùk.÷¼ErF”.ùÁâ¶õqDi]¥ìωˆˆÌcPÊ ”ˆ<\} J¿ù¢§Í£Š^·)*V*Ûéýº_Eþè¯j°ÌgòöÕȡæ ÿùsBͼ–¼»8¥ÎÛ¢7Ô¾¼;øsP{ÏÛ–kq®NA0ýtwÓçߤyøA‡}[ WìþyÅfBÍHá>ÿ¶mQ}‰›vBjæFÔ´›ÉmnOtJPzãüe‚Å…hûæ§v×Ý•RÆí»RS®šüÜRX:lŠôÙ”~cL–·Ê9¶½>no’šÚf€w³×\îyKyK+®Û2—¨þ¥IÛ~5»~Ý9G©ÒýZ]¥ìωˆˆÌcPêô t;ƒR"rkõ5(íõÏÚ•Å×ͱ«ìò¤²C>ëQçuOÜ\³Š}e…F‘E™ôƒ{Cc[Œh3ÕÕUÇçŸtä¼­½Xwz¿…4bìÁ{u~åHM¹j2dÐ_°h[ô»÷+ŽòÒ”–˜ÝÆYA©þh°eÓÚ]wWHâ9kJKÐþÏ>·Vo=Púlýü&÷o)0”sì×õúgMãüe,šiq[ýQù«Â–˜ÜÆRP*÷¼õ•Bt8œdÓý÷[˜Ÿ/-Rö:ýù7͹JPº_svPÊþœˆˆÈ2û‚Òí J”QCS_ƒRU#o”•;ô²7}È©î«#¢ë¼î«f/•ŽoËß'íoŬÅV÷7ëÛï ~š‰<µ?L²"Éõm«¾?O½pÙôh¬FÞx˜Vó“Øêê*»§•HX/]“1†šÜÆYAi·¿µ–‚G¦‚pe€´·V¶}óSi,õÓL£éT^–C9Ç~Ý…ä3Ò¶‚ CPÏ‹÷KÉyþèi¨oc)(•{ÞúÒ®ÕÜûüçÏáÛ¸¥Õû5gô ©^Iñ»ê>²Ý`hJK :<¾Ÿ¡ÈH™ãh¿æ’ ´õçDDDΠ”A)y ¿½èã‡@?Œí13¢°oë.£Ÿ4ëómÜJZÝY§Ó"qó.,œ†ÈQÓ±&2i×Rá×¢Óê­¿zwA^VGDcþ¸Y؋Ԕ+FÇ>´c4¥%8œ„¨ õ @ ¦ö‹ VJa…V[éÐ\s–Ì>MªkòžCíãuÖ{Ï[|±„šù6ã—mÄœÑ3°dê\ƒ¹Ý˰:×lç¾4\Ñ»ª}?ñqÊýÔ´A‡ô[iØ‹_OĘNC1±ûÌ œ‰³‡OÔ†<&~:<ºãרª,—¶¹ué:ÖÍ[Ž9£g bd0¢ƒ`ßÖ]¸zÆxš1†JáWA^6EÅbÚ€qôùã»úcú RH«tPªòòFx@°t|ñl]²óÇÍBx@0MŽÄ¶è ¸~4}¿] uÿ¨ Š ¤>!)~7"F#ÄoN Çá„$‹a¥þ¼ÇOÒ`yÈ"„øMBøˆï±2t1òÔj³¡Üc뫬Ð¥›¢b-nþèiiÛóGOanàLŒïê1†brïQˆ™eñšË9osûy|?ËC!< QAHÚö«ñsÒÈ[škWtHM¹‚¿Ÿ¹3‘°&åéz:{Q Gû5W´ó†ÒŸ9ƒR¥Dä.ž0\9Ýœq]†™Ý‡;¥Ã[4¿ô=¸sßbYýQ\¦„ùOsjÝü’dó±ßϰz¯^¾¬FtðÅëyþè)›ÚеöâÈyë¿X›“õè±Ù¹8õé/#šõíwN¹·#ƒmº^îÜCÏ´3¹ñ]ý‘›­¶X^«­D»·š•]mVšãŒ Tåå0ÿi(.(°züÈQÓMÞoWý$yÆ× Û2ÇTXÙñÝ/påô«e͆rŽ­ïîõ›võcýþÓɦþÅÜ5—{Þ¢®U,Ngü¬÷ç]>ü WϘ?v¹¦ ³‡;·9Ò¯¹¢7”þœˆˆÈ™”2(%"ÔP‚R•—7ÚÆ©É(È˃V[‰üœœ=|óÆ„X-;ó› œ?z/rs¡ÕVBSZ‚û©·ñSÌFôÿ_g§Ö»ÝÛŸaÝÜ<¸såš2”kÊqû.vÆÆ-È4ä³X˧ÎãIú”C«­DIQ!îݸ…=w`xë.m+¶¾XÛsÞâ‹uúÍ;X?ÒoÞA¹¦ š²R¤ßJÆ+-NI ¯Óû-¤Q{¢™ß9åšuøó˜ùMnOÄÝë7‘›­†V[‰Šr r2³pþè),™:×ê¨)Ÿ÷š#fFRŽŸEžZ mUÊ5exöø N<†¥Óæ™ JU^ÞÕaöÇ% ýVšÔ¾‹ ð4ã!RS®àÐŽ}fç•”ª¼jFð.ù’Ï 7[ªÊrhÊJ‘“™…ëç.aó¢ÕFó»:(UyychË>øíç½P?ÍDe…Úª  ãö]K<„ÕÑèõOÓ‹lµ}óS,›¾©)WP\X€êê*霯þ‘‚„µñƒN9Ç o=é·ÒPRT„Ý~6ùsz£gã/-3# OœEÖ£ÇД•Ö´Õ¬l¤ßJÃÙÃ'°cÕ£ÀJ·¨ç?ÚaǪ-x˜všÒhµ•ÈS«qê@2‚M–iýF,Š+§/ ¸ •<Íxˆ_Öýäô>\Ÿ#ýš+ÚyCéωˆˆœ‰A)ƒR"""·dË*ÉöÙn°4íåËjôþ—ý«Ê‘ý”îωˆˆœ…A)ƒR"""·¤ô‹µoãV¸}ùA‡“IG]~~DDž‚A)Õ J”¹%¥^¬ý¿êÕÑP?Í„ èð"7ýþÓÉåçGDä)”Q}Á ”A)‘[RêÅZÁ—G÷2ŒVc&""çbPJDDõƒR¥DDDnI©ë Wá≳X2e:¾ky%""RƒR""ª/”2(%""""""""òx J”y¼”þ”xعAiü¯ J‰ˆˆˆˆˆˆˆˆ§¥¯òDg¥?%fPJDDDDDDDDDÊ`PÊ ”ˆˆˆˆˆˆˆˆÈã1(ePJDDDDDDDDäñ”2(%""""""""òx J”y<¥ J‰ˆˆˆˆˆˆˆˆ<ƒRw JWovyƒ """"""""òDKWofPÊ ”ˆˆˆˆˆˆˆˆÈ³yhPzPñ T K J£”¹””FËJÅœPÙ ô ƒR"""""""""ª J”y<¥f‚ÒN JcÖocPJDDDDDDDDäFÌ¥1ë·9-(Ýè©AimXÊ ”³ø»HK<„£¿py]ˆˆÈqìωœ«¡?cÁƒ&àù35Ô™Ï0¥_ ÕíÃü§Bt&-êòó!""rÖ‚R1ßcPÊ ”ÜÀÍ‹× :ܹšêòº‘ãØŸ9WCÆr2³¤ óñý «Û3(%""² ƒR¥T4ô?ú©nl]²é·ÒPRTˆêê*‚åš2ädfáÌoDZ`|(Ú¿ó¹ËëIÔ±?oú~â#…MËC~°¸mIQ!A‡ýq¿¸¼Þž .ž±îµÁÔþc±*l Ú¾ùiž_qaÔöòÔj«Ûwý?Fµ, ñ=ƒR"""<&(ÃR¥TŸñÅš”pçjªÙQ%¢wîaPÓn.¯+QCÅþ¼a`Pê¾êâÛºd­tÿ;üù‹:=¿õóWHÇ^5{©Ýå¿mÕ—A)‘ õ!(sN×¥¯ÂR{ƒÒÚ°”A))ƒ/Ö¤1(}t/“zDP4K¦ÎÅ¥“礧G÷2ÐîíÏ\^_¢†ˆýyÃÀ Ô}5ô TååAM»a`“®•ePJDDdš½A©˜ÿÙ”¾ÊLPºvÛ/ J©ÎñÅš” ¥7/^3ùù®ÕÛ¤—§¨‰³]^_¢†ˆýyÃÀ Ô}yBP*ƒR"""Óœ”®Ýö‹‡¥[v0(%§à‹5)ÁZPÚé/-P®)ƒ èp|ïï.¯/QCÄþ¼a`Pê¾”ZÆ ”ˆˆÈ4‡ƒÒWy` J“”’Ÿ÷šã‡I‘8}ðr2³PQ®©Yð&+WÏ\@ÜÒuèñ÷¶ÒöӌÑ_’ùàÊ5e(.(À©Éöe?DŽšŽ»×o¢ª²ÙOžbUب™>®oã–Ø‹ŒÛw¡)+…¦¬÷Soc•H¿•Æk’ÍZPª¿MÚ5ã¶–“• AÐ!y÷A“e§ö+½|ž`ðY¯Û#fFü´w®¦"'3 š²RT”kõð1ü´þ_õwêù·~£ ŒÅåSçQôâ*Ê5xšñ kã1À»‹ÙrSûŶè 8ô4ßÏ@a~>´U(.(Àµ³±lúB›Á ê€äÝñü™Úª äåáüÑÓ6Û/(ÅÞ~Mß ¦Ý°{ÃÏÈ|ð•æç#åøYÌb²Þ]ÿªÂ¦¨X¤¦\Å‹Ü\TU–ãÑÝtĆÿˆ~ÿ鄤øÝ(ÈËC¹¦ 玜Ä7_ô4(¯DŸÚý£6Hܼ ·/߀úi&ÊJŠQUYŽçÏÔ8±ï0¦ çÔû]ûs9Ï·¨ÇßÛbËâ5¸}ùŠ  ÕV¢¤¨Yãê)؇îµ1[‡.~…õóWàÎÕT”•CSVŠGwÓ±kõ6ôýÄÇå×HŸ»¥®¾æ®ê×ä>cŽœ÷Ï+7[ç[Ÿ©ý„ãìáxt//rs¡­ª@IQ!Ò®¥bó¢Õfûáwî™noõžíZ½Í)÷»¾öçrƒÒa_öËÜ\«çÝåïLî?¨Ç‹åKŠŠÔ3Àå×IäA©+¯¹+û5¹Ï˜£ç­DPš¸i§Å2¹ÙjøµèmTŽA)‘ó¥¯r»º JÅ\òõ të/Ü7(•ÂR¥ Ö÷ǼˆßºtëæÆ`öði6QAؾ|’âw”_ê/<‡Qí#¨Çd=z AС²BƒeÓbTûÁ8wä$A‡rM™ÁKKÇw¿À“ôÒq/$ŸAÔÄÙóŸŠ-‹×àù³Ú€ÃÝ^¬©~±”¶~£ óó!:œL:jô¹RAiòîƒX49¡Ã¦`ÁøPìÞð³ôìU”kÐï¿¾Šžwë7šàÊé Òñ¯ž¹€¨ „ùOÃO1¡)- è ÓiÔc„Ùë–§VcMd4"GMGè°)X1k12nß•ö»{ÃÏ&ä—$i›ëç.!< ã»úcá„0¤ß¼#}¶uÉZÅï¹£ýšÊË“{ÂË—ÕJ‹‹·tÂü§bÑäH¤^¸,íó≳#ÇôƒÒ¹3áÿUÄý¸¾öúÿ‘‚±¾ßbÞ˜T”ׄ°Û¢7Hååö©¢ýq øñûù˜Òo }ü0±û¬‰Œ–Ú¸ è<È8ð“s¿ës.7(½wã¡&ÐÞ‡éC&`L§¡˜Ø}"GMGü²øãÐq“ûÑf4e¥4e¥Ø¼h5‚z xÐìXµEjÃ…ùù¡º+¹CPêÊkîª~Mî3&ç¼{ý³¾mÕ߶ꋽ[vIÇ h;Xúw}mßüÔèø³¾ý[—¬Eøˆï1¾«?}ü:l þ8t¼¶ÞWŒë=¸Ywƒ}§ûƒA)‘œ”й"ƒR¥õFç¾”FØ;ªM|©OܼKú·UaK :d>x$ý[ßO:J˜~?p¼Ñ¶‚ CÜëöïó^sé¥ÀÝ^¬©~±”.jp½þ¹RAéÔþcÊ.œ.}nj„ óÆ„HûÖNEþª(+)† èð$ýZ¿ÑÄæëæó^s<¾Ÿ!½tw|×p®ºéCjÏ{Ǫ-F?Em÷ögHM¹ZS¾´Ää¨NGÉé×Z¿ÑO3Bt(.,0áÔÈ·'šl/úAi¯v€ÊËmþÔT ‹ô·Ý—A¨¡)þ›Ü>Õšo[õ…¶ª‚ ÃÑ_ØõœX»ßõ¹?—ó|÷ûO'ÇŸßFµ×üEn.†|ÖÃhýçhó¢Õ.¿V5í¯6(݇@?³ÄþEÉ Ô•×Ü•ýš¬gLÁ¶æŒ9JõÃç×§$yÝñ½¿3(%""RXƒJ¥°ÔÙAiƒÒ†Bÿï³ÛUÖÔK}øˆï!5£ãô·_–ôÿ0}˜v‚ CNV¶ÙŸ¨qñRÂëP›?5E¿·E@ÛÁؽA îݸer$Œ3ƒÒ¶o~Š¢/¤BJž·øü¼ÈÍ…Ï{ÍMn³nnŒÙúY ˜—‡,’ÊŽé4Ô೫gjF²>¸sÏä5UyÕÌñ'–ñ›¤ØyËé×ôïåªÙKMnãÛ¸¥tÏô¯© TååGwÓ!:¬Žˆ–þmeèb£—}¹}ª-Äi2nßµúœØs¿ës.çùîóïÒgöŽ ê1B*1Òôô*/o\ý#‚ ÃýÔÛ.¿V*/àÔVJ¥®¼æ®ì×änNi•—7~ßµ¿æ¸™YfŸ{ïw}ïÏåþôþ~êmBÍ kâm^|iûòMª*Ë1¸Yw³Ï‰ØÖ´ÚJ´ùSSÅÏ?xð¬ [bR׿ªŒ¶wuPêªkîÊ~Mî3¦d[S*(íòáWèúWÚü©)7ë.í3jâl‹å”)Ï– TÌù”2(mðÄ…N.Ÿ:owY9/õ#Û –þX]77Æì1ÜõÅšêkA野[|ásvP*¾ø™ ¯5¢Í é¸13£,n[RTAÐáÔd“×Í\p¦ÿÒ©ÿrëÿU»ƒ”„µñŠ»œ~íôÁc„šŸÝ[ÚNtåðÖ¡òrŸ t\—aHÞsyjµ– BÍÈbqžRýãʽßõ½?—”ú5ï…œÌ,i›êê*\H>ƒ9£gX êOî?b÷sb*¸”+y÷A³ÇókÞËh{w˜£Ô×Ü•ýšÜgLɶæhPêÛ¸%ÖÍÁ½·¤¹R¡&”Í|ð¨¶o±òŸ? J‰ˆˆ”Ç ”A)é)×”AjVhµ·¬œ—ú‰ÝköäH³Çp×kª_Äè~êmø5ï%ç’ËS«Í®ä­òr~P*¦Â+Gé?c '†[ÜV<¿+§/˜¼næ‚3¿æ½L¾Üê<´Õþ¸ÅÎ]N¿&.~¥Î|fq»¨ ©î»×,„åAéúù+lºÞŽ¥æîw}ïÏå¥*¯šÑq[—¬5ZQ<7[ØðM†wâHr{ôý¤£âç_ƒRW\sWökrŸ1%Ûš#Aiÿÿu6C-aPJDDT÷TPº}ß· JWm¶?(ýqÍ—7O—Ÿ“Axµz³eå¼Ôëv[²Èì1ÜõÅšêsÐÏzH¡ÚO1Í–Ï~ò‚ Ãɤ£&?wÇ Ôð³f86¢Ô\p¦ì…Âêü~Ëé×Ä¥%E…·sÇ¥úANn¶ Ƈ¢ï'ÑîíÏàÛ¸%üZôÆ¥“çJë{.çù~]ûw>Gx@0Îüv\šûXt¸ué:º|ø•ɶ¦~šéòk`w Jëúš»²_“ûŒ)ÙÖ JõƒÚƒÛèó :ð%Ú½Õ =ÿÑáÁ J‰ˆˆ\HÌçì JWmvŸ tû¾#õ7(•ÂR¥nãÆùË„šŸ™š[˜ÀS/õ}?éˆ0ÿ©˜õíwÛ¾þRßùƒ/Q]]AÐáÐŽ}fá®/ÖT¿X €Ä—¾Ê úÿ¯³Éò·ïBtHM¹jòsw Jõç(MÚö«Ùíxw‘êgï¥æ‚3߯­¤cë÷uEN¿¦?Gi¿ÿt2»ÝÁ퉄š9­ÍQ:¥ïh„ùO5gkPjkŸªòòFâ¦R5íf±ÞJ¥õ½?—ó|[Òçߤ9aÁxnÉŸWÔ´µ—/«ÍÎìŽÜ-(­«kîÊ~Mî3¦d[Û+]ßNï·°º}¯Û„¤¦¶Ñÿ²”ýõ@MèkeÔ¿)ß|ѳ6ì¶òK """OòzP*æw J J¥°ÔbPÏ ÔM­›·\ú£qÙô…v•5õRoŽ©—zñgÏ¥ÅÅfçÂr×kª_,@ÞoüçÏ!:NH2YþÔd‚šÒ´çs£ÏÝ1(UyÕ>?…ùùÒb>¯Û°`¥T¿)ýÆØ|ÝT^æƒ3•—7RS®¼™Y„o[§÷[N¿¦/×DF›ÜÆ·q+…kæ‚RSl JÍ1Õ§Š#­4¥%fË9#(­¹ßõ·?—ó|ÛB¼6¯;SúJûݽÁå×ÁVî”:ûš»²_“óŒ)ÙÖľKtòY«Ûëâ\¶Ää6ö¥‰›wIÿ¹Ùú&vÕ½÷¿:HÇY;gYÞ?"""wf>(·”й`½ JkÃRÛ‚R),ePêºý­µô³[mUæ›esY¹/õ‘£¦K°ž?z ß5þ —»¾XSýb-çuÔé´Ú²Ñçú?³6õ³Gw J猞!;)~7T ?Ùn04¥%ßÏ0z锜…ø^ú,õÂeôüG»:»ßrúµÖo4ÁãûRâÿU£Ïü’$[ä¨éÒg®JÖÄKÇÓi¨ÉrÎ J•îÏ}·Â‰}‡QZ\Œ‹'Î:5”’ó|«¼j‚ KûO½pÙô¸FÞx˜v‚P3µB}ù)°;¥®ºæ®ì×d=c ¶µéCj¿ÓVGD[ݾÛßZãåËêWõ>mô=¤ò²/(]5{©´í„nÃí«#oé;ïõ9¹‰ˆˆ#7ëÑc¬Ÿ¿áÁ˜3zVGDKs 2(%9¬@]ÿª’^žŽïýÝèóFêtZ$ÅïFÄÈ`„øM‰á8œPœ¹SPªjä-ÍIY3úñ ~ü~>æÎDšxT”k¤s2õÂ)'8Sy®´\RT„ýq Xü]$ÂG|ùãfaST,®œ¾€Ùç)~Ïí×T^Þê ýÄVSZ‚«¶`ÎèX6}!î\I•ö™r샗~W¥c: •ι /›¢b1mÀ8ú|ƒñ]ý1}È)@R:(Uº?[ºNÚ— è°gãÅÛˆÏ÷ ¦Ý¤öµ)*3¾žˆ1†bb÷˜8gŸ¨ýÏ S`Œîø5ª*Ë¥mn]ºŽuó–cÎ舌èàØ·u®žqŸPÇÕA©«¯¹Ëú5™Ï˜RmÍ·q+iÕzN‹ÄÍ»°pB"GMÇšÈh¤]K…_ Ã>õüÑÓ!ïÜÀ™ßÕc: ÅäÞ£33Êæ Ô_5@Ú¶ /«#¢¥ëžšrÅèØ¯G BÍnóÆ† fFömÝå’©bˆˆˆÜƒR;‚R1,µ?(ÝΠ´ž óŸ†â‚ƒSSôGOÉJ½jþà>wä¤Õã2(%9¬@*¯ÚÑx/_V›\éyÆ×  1Ç­‚R¯š•¡¯ž¹`¶¾åš2³/ôrƒÒöï|ޤm¿Z½f›¢brßé×D#ƒ¥ ٔ˧Î÷q+ƒ2®JU^ÞXm›£xPê¥l..>#J¿•æ”6"rôùŽlµŒ èðàÎ=³£ÇwõGn¶Úby­¶íÞjæÔk`+W¥®¾æ®ì×ä>cJµ5ýQئ„ù~§ôûO'i¤¾5Ö‚R•—·Á¨~kÇ~ÝÈvƒÍöíîÜwùóEDDä ¶¥Û JÅ|±^¥bXjOP*…¥2ƒÒh¥n§ó_byȸ|¹ÙjTU–CSVŠœÌ,\?w ›­6˜J‰—zѬ¡“qê@2r³ÕÐj+QY¡AžZç/#am¼Ù€‰È¶¥ýÿ×Zm%A‡?í1¹ÍЖ}ðÛÏ{¡~š‰Ê ´U(.,@Æí»8–x«#¢2W¥*¯šŸ‹/Š+§/ ¸ •<Íxˆ_Öýdv+[®›µàL4ªÃ$nÞ…GwÓQZ\Œêê*àöåHXÕ§Ý{{û5}ƒšvÞ;õð1*+4(zñOœÅÜÀ™&>êA©x½÷Ç% ýV^äæB«­DqAžf«¶˜œþæuíÞþ ëæÆàÁ{(×”¡\S†ŒÛw±36¼»X-?ªÃüqè8 óó¡ÕV"?'g?ŽycB\þ|¹‚’*”й¡=A©˜O:7(}–š JkÃÒׂÒ{”‘˵}óSĆÿˆÊŠš‘_‰›vº¼NDDDDD ‘K‚ÒW9äëA©˜[š J_åî”Æÿ*+(Y¿A)Ù$< æ'Ö/_Vcxë.¯QCd*(Y¿M^Pú*Gt]Pº×5A©–Z JkÃR¥DDDdžoãVñ›„ä=¿I?ïÞ½Áåõ"""""j¨,¥b®g)(óÁ:J÷2(%""¢,¨Ç) Õé´ˆ[ºÎåu"""""jÈ”:9(­ K-¥¯ÂR¥DDD$òmÜÓîcï–]N] ‡ˆˆˆˆˆjè¯xo-(s? J7Ê J·ì`PJDDDDDDDDTO8”¾Ê J7ÖUP*.èd>(=h_Pú*,ÕJ×nû…A)Q tP*®xo”¾ÊmJZ JÅ…œê]P*†¥ J‰ˆˆˆˆˆˆˆˆÜ‹µ TÌ÷DP*†¥rƒR),ÕJã”ÕWŠ¥qÆA©˜'Ê JÅ|³‚Ò$)(•ÂR™A©¸ “¥ T K”¹Ì¯­xo-(r’”Šy¤’º$(tR:(•ÂR‹Ai<ƒR"""""""""7a:(·”Šy ÒA©¸“G¥Ñ J‰ˆˆˆˆˆˆˆˆ\"º¡¥RXêò t;ƒR"""""""""7e[PºÝ-‚R1÷¬ó T KÍ¥RXjgPj° ƒR"""""""""—y=(ç'µ7(óBsA©˜7Öû T K奯/èÄ ”ˆˆˆˆˆˆˆˆÈµÌ¥bž''(sÅ: J¥°ÔBPZ–Ê Jã5 JŰÔî ôUXêêADDDDDDDDä‰ÄÔ‘ TÌ ‚ÒWù¡Ü TÌ3-¥b.*;(­ K÷KaéÆ{±qÇ^E‚Rý”¹[ƒR1ï“”¾ÊkCÒýRHÚð‚Ò-;”Õv¥¯ò¿ú”¾ K•JÅyJm J tbPJDDDDDDDDä,¥b®gkP*ÎOªxPú*ç´/(Ý«LPºQ?(}–*”ê/èäêADDÆÂü§Bt&-êòúQòdê\ßû;~ßµßåuñd!~“pîÈI¼ÈÍ…¶ªÏŸ©qóâ5ìXµßõíÇ~pçžÉ~)ûÉS—_?k–‡ü€³¿DZÄCu~l¥ž±àAðü™êÌg˜Ò/Ðå×”ˆˆˆäÓ_ÈÉ)Aé«|Q~RÙAé^ł҃¥RXª”Æ¥† :½”Æ3(%"ª”R]ºs5‚ ÃÍ‹×\^Oµ36Îì3/:¤]Ku‹c×ç Ô•í\©cçdfI×üñý —_S"""’Ï8(7”Šó“¥qÆA©˜#:”T.(~ïHP*…¥¥¯/è$®ˆÅ ”ˆ¨þéú*Œj?X>â{ J7뎄µñxpç>4¥%¨¬Ðàù35.$ŸÁÚ9ËÐ￾Fe6EÅ"õÂeä©Õ¨(× \S†œÌ,œùí8¢ƒ Óû-,sÕì¥HM¹‚Ül5*+4´UÈÏÉÁ…ÿoï>ÿ¬*òÄ£;é·Ž3»;3»v1Í †F…³GTDI‚Ì(*APD *Y,©A@’‚(PÄ "©&4íý¾¿Í9ÜpBU:çÜîûyð~Ý}›Ëi|ÕÇoU-Y):?)ñ—À¯Ñðô³¤Oûî²fÉJÙóý÷Ruü¨<°_6oü\Ê'¼.Ýnï$ O?+õ÷7[]¥Wýæbé|c{Úc€\ò“sRÿ~tt¾±½ûó½g×.yñ±gåÁæm¥GˇdèãÏÉÛó–È´Šâµï8ÿúœ›Þë]Bi‚¯]±Ÿû÷õÃΩ¿§ ºðPê}ã}”Pš{ã½^(u¶Ý‡R'–z‡ÒòÄCiÎ9¥„R¨î¼à†’ ¥=Zv–#•‡§Üö|ÿ}Apô›vsTìÛ'ßýïë¾·|Uàçg2Õ²}ËV¹ó‚Æ ¥_nØèùº};öpÿ&½8&ç÷®øõEnŒ]µp™\üog{~ÛÿrMêïq>BiŠN«/ÕÕUžÏTmxmBiñ¿6(n6B©Ó ³C©ç÷q‡ÒIs{†R7–ÆJ'Ì(¥9: ¥Ù:J v+¥PúѪ÷$“©–OßÿXûsƒBiY½úÒ¢ÁurüØß º°PZV¯¾|õÉgžaè×Þëþ=tÓ}©¿:êBÄ©­¡ô’Ÿœã~ߪu¯M(-þ×ÅM%”º7Þg…ÒüïGŒŸVxã½ÅPê^ä”J'ÍYs(<;Z(;¹ ”æžSújÎ…Ni?JK§kî‘%¯Ï—ï¿Ý)UÇʾ~Õ‹WHÏ{‘²Ó ?þÕ#Ý…|ŸöÝ=¿f“3Èö-[Ý-×~znÎï_õ›‹eÖ˜©²qÝzÙùÍv9|°BŽ;"ß»S–ÏY䵺é>ysz¹lß²UŽT–Š}ûäíyKä® ›KïÖ]äó?‘ãÇŽÈwÿúF†öPðý_ýÛKdh²löBùzÓ—rðÀ©ª:&/Ö*cŸ!Wÿö¥÷-J(Õ}ϽLzqŒTìß'[>ûBîmtk¬ÏȦj‚†5ë´?7,”–Õ«/³ÆLu'Vó·À«„Ò¯¼æþ]49ãÔåP]nëèþúƒ7´‰ü>$ùž;ç«O7ɰžÏËglÊC¥òÐAÙ¼ñsÝo˜4=óüÀ¯Ñðô³äéɺ·W˽{åè‘Jùfó×2í¥ rSý+B¿‡[ξR^9I¶oÙ*ÇŽVÊþ={dí²UÒ§]wßçtÒ‹cBσÍvÃ/õ}TÕä— ´¾ï-;ík›„Òž÷<"«-—­_l–½»w»žmúhƒŒé?<ôßÅ«{‰Œ}v„l\·^*öï;ùïê~Ù±u›|øÎZ™2l¼\õ›‹}ŸóÛ¿•¥³ÈÎíßÊñcG¤bß>ùä½ä…îý¥ÑÏÎ+ºŸ1¿³—UßóÎ7¶—WޔՋWȶ/7Ëþ={¤êøQ©Ø·O>Zõž êÒW.ýùŸSÿ¹ Tå^äôªï÷/Žö¸ñ^7”fÝxŸz(=Kçå]è4×¥ª¡4çœRíP:P qñY0yNà‚|ùœE‘ó’Ÿœ#Ö~(™LµT:è¹myæ¨Éîvj¯Kv®ýïKCcÀÔá¯|žßÅ>UUÇ<}t¿a9ŸÿÈ­C_÷PE…û"Ögå­òÅ’ÉTËñcG´·©«„ÒN×ÜãþYžhÓÕóï<(”fO.fŸSÚ²ì&÷×ߘ4;Ò{ô{îDœ ;¿Ù.·ž{•çç7û2wØËÑ#•5aÞçõŸhÓÕ=—Öˇ+×Èß~uaÁçJÓm“P:kô”À×ÜýÝNiÑà:ÏϽëÂæî¹ªA®øõEFÏù†µäübø‹JU^{ãºõ¡ÿ3Ä#øÆ{õPêl»W ¥Þ7ÞÏ+¼ñÞ$”º±4P:¾0”æžSJ(¾7§—» ²ß}_zÞóˆthÖRúvìáneÎdªeÜ€— >÷¦úWÈÁû%“©–¯>ù,g[í×·q/ØÖóyßן;~š<ÿðSò`óvÒöòrÿU­dDï²Ï÷µóƒ¥ÍÞë]i}é­ÒéêV²cë6Édj¢ì .}¥õ¥·Ê»o¾%™LÍ­ÑÙ‹óìØõæôréÓ®»týûýÒ§]wY0eŽ{6`UÕ1i×äŽÀ÷Ï$”Fyϳè=0gA]]]å{þ¦ Þù€ûZ;¾Þ&­ߦü¹*¡´é™¸_úË=ÿ΃BiväÉŸ>Ë~_' c<¥•ô{žRvíøNÆô.=Zv–~÷?.k—¾ãþÞ¿¾ÚR°­½áégÉ+ÖäDÍ~zI–ÉÄÁ£¤òÐA÷ÏÐéêV¯ýÏëZ»?Ç**düs/K–¥ÿ?{ˆ5ëܯûÞòU“¥×þOc¹ó‚äÎ nÙc§º{Ï%·º¿ží’ŸœÛ{¨£áég¹ßSv`Ÿ;~ºç÷ÝôÌ ŠöµMBé£w> ã¼$=[=,šµ”¶—·ÇîzP…ØÙÄ IDATÞY°Ìý~>û`ƒçç~±þS÷ßÍ)ÃÆK—Û:J»&wÈýWµ’Þ­»È„A£äËŸóC2uø«òì½åÑ;A]úÊæŸ»¯=q°ý#¢üŒÝzîU9'ÎÇë†ÒvJïÖ]ä±»”!>›óç~}ä¤Ô6(Eª¡ÔÙvŸJ=.rJ*”:=T/”žŒ¥º¡tTv(=K«‚BiØ…NΞ}NiÚ€º/{Kòä¡c bG£Ÿ—35êµ0üî‡Ü¯1kô)«W_þö« e×ö’ÉTËúÕë¤áégiow^pƒT?*™Lµ,ž1/ç÷œh–}»úÐ$“©–í[¶º¿vÃ/s¿·‡oîàþzv(í|cû‚×î|c{w:õëM_nƒ× ¥6ÞsÇ}WÜ•í>~÷ýØŸg{|&S-'N—Å3æI›Ëþúy*¡´¬^}7/™ù†çßyP(ýzÓ—’ÉT˖Ͼôü{ÊŽï;¶n“ÁÝúiOj%ýž;!å__m‘Ëÿý¯¿?qð(÷{Úc@Îïõi×ýÔÏfÖÏŠ£eÙMrø`…ûõ³Nž~–|³ùkÉdª¥bÿ¾Â)ÂÓêËü×f¹_ÿɶÝ|ÿ œQšÎkÛ>£4ûðäO”7ÿS÷÷ò'øUÚ䌧žÅ}ûB'íM_Ûäg,ê{ôç¾üßÿ*Û¾Ü\ó߂Çä²ÿW{~v¨+òÏ'Í ¥öo¼×¥Y9Õ¹Pêu¡SÚ€ºïÕkN†¥/|'º²·CwoñÏ™;~ºû1=ZvvJ塃¾[‚U8[†7oü<ç×½BiÏVK&S³•8ûc”1ÃBiY½ÜÅñƒÍÛú~º¡ÔÖ{îè{OY¿z,™¹@šÿ©I"ÏMßû{ÊÁr‚á‡+×¾Oª¡ôÛmÿ’L¦ZÖ.[åùwîJuéë~/cú÷ü˜ëÿÐXÖ,Y™ó}WìÛ'ã¼$WþWC­?RïyØE3~vž|ÿíNÏ@üÉ{I&S-{wïö @eõêËËOöüYè|cûSqèñç”è3’¥~9Õ„Òùá¡t¶f(u¦J“¥¾: ¥Ùç”J¤¡åE7æ.Ó^šøõŽ9uéK~èòsßwÉ’™ ä‡;sÂÕÞݻݭһv|—ó9I„Ò²zõåPE…ÿü>F'”Ú~Ï‹Á%?9GžhÓÕ=j!“©™.Í?nÁÖÖû Û·lõ¼4ÌÏÍg5““ç¸çpž8q\¼¡Mêïi6•ˆórŸÜ÷àžKn•²zõ¥ÕÅ·¸¿6¸[¿À×p¦ƒßž·Äýµó—J&S³í>ès³'Þînx³çǤJ[üõZßgeÉëó•žíR ¥MÏ<_^~r°|±þS©<|ÈýªªŽÉö-[O…Ò¬O³ßïìNœ8.k–¬”'Út ½±>ì9Ï>³Uõ,hU¦?c6Þó°×Îþï‹Wœñ ¥îENY¡ÔóÆûBiþEN9¡tä¤9óUC©Kt¶ß‡…Ò  CéXõ›ïÓ~ ÔmÙ“*ªæŽŸæûõ®ù]#Ùóý÷îÇ~úþÇ¡´¼òÔ¥×M+”:Û-×½½Ú÷ctB©í÷¼˜49£Aζöü›ÔU/sr¢åŒW^óü;Ïvìh¥ìþn§¬^ü¶ xð ßíåa¾¹ƒ{îÖ/6§þ^fS‰8Ïü£·ûžÜUÍ¥L÷_ÕÊýµ¾÷÷ | g*øƒkÜ_s.Ú¹ýÛÀÏíשWÁkç#”êK#”Þøˉ¡A¼BiY½š Ôq^’½»wç|üîïvʰžÏûÓ°ç<ûïÒïµM™þŒÙxÏÓüs€p6n¼1~ZøEN!¡ÔÙvï„Ò시ÂBéÈIsæJ@AöÄYߎ="}­†§ŸåÞöë§L¦ZF?ã©Gv4ÜýÝNyºÃcrÃ/“F?;Ošžy¾´hp¼ÿÖ»é…ÒÓêËñcG$“©–•oxßÔ\VO/”Ú|Ï‹ÑÕ¿½Ä*ο€K%”fŸÍÚ§]wÏ¿ó Ëœ¢ÈÞjžQMšT"ÎGŸu¿wgª3ûY{¡û3¯4QzðÀþÀÏ-æ‰Ò¨J-”®{{µûšó_›%m/¿]þö« ¥ÑOÏ•k~×HzÞóˆr´»ôç–ž÷<"+ßX–óß„OßÿX®øõE_ì¡ÔëgÌÆ{N( ¸Õ¹PêÄÒüPêÆRÅPš¡SX(õ;§ÔyãüÎ)uÞxgû}Ú€º­é™¸[ݽnÄÖáL†þøã ér[Gy{Þ7Z¶½¼…ççÌ=E2™šóìn9ûJÏq.…R ¥7üñ2éѲ³|s÷ïñë‹gû½JÄq~N²Ï Í>£´üÕ¾Ÿ{Sý+Ü?·ß¥AV9¯]]]å{Féè~ÃܯÕä— ROUÕöPºxÆ<Éd§‚ËêÕ—kÿûÒœHö¬èD»ëÿÐØ=o:“©–9ã ÿí+öPêõ3õ=OûÏ ÂéÜxŸJ=Î' ¥>9©„Òü‹œœPêtQãPz*–ÎË;§´0”&u¡SÚ€ºoÃÚNN«{‰Ñ×èЬ¥œ8q\2™j™8¸fAßì?ÊÜí¼Û·lõŒ#ÎäM塃¾_['”ú1 ¥£úu?¦GËξ_ÿºßŸºíù¥'%òžg{ºÃcòñ»ïË’×çk]ž—­_l–L¦ZÞ[ž{k}X(½í¼«åØÑJß Þ¸Ciö´Ü}WÜU4ïyXH¹â×¹Ïø†µäüžsëýþ={Ü Òò|úE÷Ïý`óvî¯gßz?¢÷@ÏÏmzæR±ßÉ×þÐ÷ÏðB÷gܯuÛyW§þŒªªí¡ÔùGTœœ/{2~hžcJÖ~èmÃkÿ§&Ì®_½Núÿ³wè÷åg,߬15ïù±£áï¹í?7°¯¨o¼JÝXJ(€=[=ì.Â6¬Y'×ü®‘Öç7=óÙùÍvÉdªeãºõÒè§çº¿—ZòÏ›,«W_¦˜àþ~»&wx~ý$Bé3ÿ(\HßrΕî¥Bû~øA.ýùŸý_ã´úRyè d2¹g<ÆõžgkßôN÷ke2Õòá;kc}^Ú^ÞÂóF{¯÷Չ掠PÚü›ºµêøQ¹·Qáe)QBi“_6ð}ÆÊêÕl^¿zûúAcI¿çA!¥ñ/þ"«.s¿—^÷æž ûD›®îï•Ox]ÊNËýü{Ýê>»Û¾Üœvž~–lûr³õ[^tcÎç6<ý,ysz¹ûõ{·îâûgèrÛ©çbx¯±¾_6ÕöP:ôñçܯt®fY½úrå5tÏ^½xEÁ³RV/<”†]¤¶aͺDBiöYÉ™LµtºæžÀò3ôžw¼òîп#B)Å­6†Òìm÷ú¡ôd,U ¥ù甆…RßsJO†RÿsJ ¥’óÖÜ7Ý…ØÁdîøiòì½¥g«‡å©û•Ñý†É+ÖÈãw?Tð¹sÇO“L¦ZŽT–¿ÿ¹pRlÑ´šR]]%í›Þ™ó{íšÜá.Ì÷ýðƒŒî7Lºé>i{ùíÒ¡YKér[Gwag(ýñDzjá2yî¡>òD›®2aÐ(wJ.“Q»aÙ9j “©¹$¦Oûî2¸k?™3nªç÷å=Ï6¢÷Àœ P]]%ÿÛÙñ<+§Õ—[·Éჲpê\éש—7ŸÕ,çóPúùǟȃÍÛI§k÷<"³FOɹ]{P—¾ž¯%”>Ýá1÷µÇô.Þù€tºæéÞâ2¼×Àœ lfžR<ïy½S!eÏ®]2¬çóòøÝI–eTß¡òí¶¹ßÇ»o¾U·N«ïžóëLÃ=ÿðSòdÛn2mÄ÷<Ùêê*ϨÓéš{Üíû•‡Êä¡cå‰6]eP—¾òÙܯ»vé;žaÍÑôÌ Ü¿ãêê*™5fªôíØCz·î"#z”Mm ®í=4UÛCéÝ ov¿Æžï¿—º÷wÿ}Y¿z´hp]Îǯ^¼ÂýøÕ‹ß–'Ûv“ÍZJ»&wÈ?¯k-ƒ»õóv·œ}¥d2ÕòÕ§›dt¿aÒõï÷K»&wÈýWµ’'Ûv“U‹–ŸŠöGAØ †Îdºct?ÿ³²#ÿŒåiYv“ûñû~øA†÷è¾çÖ~PðœJ(nù¡Ôó|ÒXn¼W¥Yç“ÆJçç…Òô.tJûP.ýùŸ¥üÕ9 K/ù‹Íû®¸Ëý½!>ëùµ¯û}c9TQ!™LµlúhCÁ"sDïn, g(õóã'dLÿáJïá½nu£S¾-Ÿ}ií=Ï×õï÷‡¾–-·œs¥©<ú=<°_¾¹CÁç;¡4èóžhÓÕ÷õ£„Rg r˜•o, ½l(É÷¼¬Þ©dÕ¢åÒôÌó=?ÿŠ__$®\ãû¹G*ù^÷>âûlg2Õ²îíÕSÆŽìKŸ¼ôhü?ÒPÛCiY½ú²dæå÷¼ùŸš¸SÄaò£]¯{Qú¼-Ÿ}á9Eo3~þñ'ZÏVÔŸ±|Ù“Öaï9¡€âV 9Õ„Òù1…ÒÙj¡ÔëB'Û¡4wû}a(üÊ«©?JKëÆ·É¬1Seëç_ɡР9qâ¸TìÛ'×­—i#&H˲›N}üi§x_}òYàD]öYŸ^Ûs[7¾M掟&_}ºIöîÞ-UUǤbß>ùfóײaí²`òœ‚)C›¡tô3ÃdùœE²g×.©ª:&{ví’åsI‡f-µß¿w,“ý{ö¸_gÕÂe··¿ç>&'ì—¯7})­ßë3rÕo.–Ÿ”åsÉŽ¯·É¡Š ©ª:&öî• k?Ñý†ÉµÿÓØós‰ªvî”cG+åè‘JÙ¹ý[y÷Í·ä…îτƶHg”žVs–îä¡ãä“÷>’=ß/UÇÊ‘Êòãëm²äõùòÈ­•¿^’ïyçÛËô—'ÊúÕëd÷w5ï]UÕ1ÙýÝNy«|±t»½Sè×hxúYòt‡Çäƒk¤bß>9v´R¾ÙüµLy¢Üø ýü[ξRfŽš,;¾Þ&ÇŽVʽ{å½å«äɶÝB'ì²u»½“¬^¼Âý9¯Ý$S†—›ê_QðñMÎh ƒ»ö“÷–¯’[·IåáCrôH¥ìÚñ|õé&Yµh¹L:Vî8?w2²ñ/þ"Ýnï$ó_›%Ÿü‰ìþn§TU«ùÜí;dõâ·e@ç'}ÿG„Í`xwÛå«O7ÉÁäõ‘“BŸQ?cÙýì©Íï³BéÜù“˃CiÐ…Nù¡4Ò…NÎ)MûJ‘óI£^äåÆûÉåKdôä¹y¡ôd,õ ¥¶.t²}NéQS €R”=Mÿù¤Ñ/rÊ¿ñ>0”†^è¤Jã½Ð)û}ÚPŠ¢œOý"§è7Þ+…ÒØ/t2<§Ôkª4í(EFÛîCÎ'Mò"'+¡4– Î) Ú~Ÿö”"¥m÷Ï'Õ¾ÈÉj(µp¡SÜÛïÓ~ €R”ܶ{û9„Ò)åKÅ¥!¡4ÎsJó·ßg‡Òüí÷¹¡ôµÔ eO“¾8ÚÛ}~(Í™&Mè|R¯ï§”/õ ¥'c©Y(Jc:§4í(EiœOZJ=Î'5¸ñ>4”Ú¼Ð)ò9¥ ÛïÓ~ €R¤³í>®óI£\ä¤Jgë]èû9¥yÛïÓ~ €Rä·í>íóI'Ì\¨t>©Q( ºÐÉÿœR½Pjºý>í(E‘·ÝG¥^Ûîu/rrCéØiåó¦”/{:©Sj{û}ÚPŠâÜvËù¤y9M)_*c§•Ïó¥y±Ô7”Z>§4Êöû´ ÙØvçù¤N(õ›&Õ ¥a:Ù>§Ôdû}ÚPŠÒÚvz>©âENf¡ÔøœRïí÷#-n¿OûJ‘­m÷#•·ÝÛ=Ÿ47”Î[æþ¢j(59§ÔÖö{¯©Ò´ M“ÚÞvoë|ÒIsOEÒ)ó–y‡Ò$Î)cû}ÚPŠ’Øvçù¤Ú¡4–sJmm¿;9õ(Ea—8EÛvÿù¤æ¡TùœRïí÷ù¡ÔÖöû´ űíÞÿ|Rÿm÷¦ç“Z ¥Å°ýÞ‰¥i?@)*˜&-²m÷¡t~M(µpNiœÛヲJ ¥@º‚¶ÝçO“&¹í^õ|ÒšP:_/”fÇÒ Pz*–æ‡ÒèÛïý¦JÓ~ €R¤2MjgÛý¼Ðm÷f.Ôž&J ¦J}Î)mûýxB)¶ÀKœâÞv2”FÙvïJ½b©æ9¥6·ßë\ê”ö”¢(—8Ží>?”zEÒœP:uþrÿPêKCBiØö{'–æo¿7*MûJ‘iR'”zM“jm»Ÿ¥?M:uþòˆ¡4îí÷—: 75õ(E*Ó¤¾—8Á¶ûxB©òö{û—:¥ý@¥(©Kœ¢n»W¥µfûý„žÛïÓ~ €Rä¹íÞkš´H·Ý»¡tÜŒ7ÊC©Áö{›—:eO•¦ý@¥ÈdšÔô§8¶ÝO¿\ÆÍx£Ü~(µ´ý^wª4í(E6¦IÓÜvJb©j(µu©SØTiÚPŠŒ¦I-\âJU"©g(öÆrIgû½½©Ò´ %5M×¶ûioÄJ /uŠ2UzÙç§þP¥ä²3ÎešÔä§ØC©R,5Ø~v©Ó¨€Pê5Uzퟚ¦þ`¥äÚ?5Uš&uB©ÿ4©Þ%NÆ·Ý«„Ò¸§Jöß;±Ôwû}ÈTé½W¶JýÁJɽWÞm4Mê„Ò°iÒ¸/qrºè¸o”ןP(Õ¾ÔIsª´w÷gR0€RÒ«ë3Ö¦Im\âdJÇ«†Ò¤.uŠ2U:lÌiöÛF©?@)¸öOMeèèI±O“Z»ÄI'”&9Uªt©“ÆTéK¯N—§z>Ÿú”‚¾}^(ˆ¤Q§IkBi²Ó¤y¡ô­ÄCi\g•>ÜîÑÔ .{¨m÷DÎ&M&”¾¥Jc‹¥Á¡40–L•Ž?Miÿ˜”–þÔ)§Õ—‡ÚxGÒüPêIUBi\‘T+”ÖÆ©R7–ž ¥#ÆO“§ŸxA®þýeé?<@põï/“§Ÿìö7'”m¹/þiRÏPª¹ý>B,U ¥Q¦JGŒŸ&ÃÇO•ÞÝúK›ëZË g_)—Ñ õ ¨ .ýÅŸåÆó®‘6×¶–^Ýž‘áã§DÒ8¦IP%’êl»?Jg.ð ¥µrª4+–?µÆ¸ÃÆN‘ac§Èб“kŒ™$/Ž®1dÔk'M”!£&Ê #'È #'ÈàW¯Ê —ÇË —ÇËÀ—ÆÕ1VŽ+ÏŸôÜð1òܰÑòܰÑ2`è(0t”<ëxq¤<ûâHé?äé?äyfÈËòÌ §ôü’ôü’ô4â¤á®§Öxêùa' •§ž*}ž{Ñõä€,Ïq=ñì ®Þý×xf«WžžýžÒ÷ù?ý\ާxz¬Ï³žíÓßÛ“áº?ñŒ’n½û…蛪®½(”öz5l=­º.WYãûõ¿žàל>áÕ.òûFvûÈï"ÙÍÄé(Ùm%»¹d·˜ìFãt§ã8]'»õ8ýÇéAÙè™!/»ýÈéIN_rz“ÓŸž>ÆíRN§rº•Ó±¿òªÛ·œÞåô/§‡9}lè˜In7s:šÓ՜ΦI‹}šÔ3”Î\àJM·ß'>Ur±“XªJbé X:¢ –ž ¦C ‚©J,uƒiÞ`0Õ¦>áÔï¹ÀpªOuª~P-®À €½õ®éºZuÝ´öjAaÔ$ކÒ“‘4¿§„EÒìV“Hs#éÿH:Ä<’ê„Ò¨‘4ÊNqM“FÝvïJ÷ߧ1UšKu§JCc©å©RÝXš?]5–&LM£i¤pªP£†Ôø‚+ÑŽÞÕ]«¬éµÃ¨IM(ÚŠ¤Ù­(®HªJu#i`(5Œ¤V§I¶Ý»¡t⬅s§/xÛ7”ÚØ~ŸK£„R“-øn,Mr ¾…X¶ßj0 Ù’%šª†Ó°xªP Cjq€$ÙX+ë¬ÍÃÖùA ,ŒšÆQ•-öviáVû¨‘4é-÷F‘ÔF(Í‹¤qm»Ÿ¾àm™8ká\Pªv©SšS¥~±Ôxª4ÅXªwn©þtiÔ`ª4eªMu©J<Õ¨1Uj½kk•µ{Øú_%ŒªÆQÕéQÓ@jeŠÔï<Ò"‹¤J¡4ŽHašTç'ÏP4Uê†R—:)ÄÒX§JŒ¥ªÛðMc©ñt©a0MµÂ©B–Ú™.!˜*FS“pªO=ªfD#¨P˜®¯½Öê*kü F FƒâhrToŠ4HW(;’Æ5MêJý¦J•/u*‘©RÛ±Ôt+¾­`t†©I4µNuªoDS‰®€b÷z7h­­º^WYûG£ºqTó RÝ@jºÕÞ~$eš4hÛ½ÓECBiø¥NE9Ušà|ÕXZpÉ“f,5™.L¦LU¢©Q8! jÕã*‰R\›®·£Q£0Gu§Gõi„)RH:P3’Ö¥-÷FÓ¤—8å…Ò7sBi¤©RçŒqª´®ÅR[ñU§Kƒ©b4 »*,œ*ÅSÅ€j#¦Z ­¤ ޵°îz\eÔ‚ÚBPU‰£&4ê©òVû:Icœ& Ùv6MšJßÌ ¥&—ÆOÛIDAT:éL•ËüÄc©ÇVü熱>]uÂÔ4šF™6 §ZÕ ¢&V(66ÖЪëu•µ¿JUž5Š£æ¤6§H=#iVcJ,’Á4©ÓíM“zo»Ï ¥+}BiòS¥©mÁO!–*mÅš.M0˜F¦á4$žªT­ˆCT Î1\g«®ãÃz@~?PžUŒ£qR)RóH㎤im¹Ocš´0”®ô¥±N•Ö’-ø¶/xÒ¹ä)l+¾Ît©N0+š…S“xªP#‡T‚+ 6‰yý«»WYã«FQß0j9ŽêR“)R•­öA—6Y¿¸©–l¹{šÔ#”Zœ*U¼ØÉ ¥1lÁ·u^iœ±T{+~âÁ4B4 §ÚñT1 š†ÔÔ+)°µnÖY«{­õ¢¨OÕ£iR¥­ö1FR[ç’Æ±å>‰›î½¦ICiS¥æ;ÙÛ‚ŸV,5ÝŠo4]ªL£ES›á4,žÚЍqEUê‚(klݪE#‡Qó8ªHãœ"-ÜjŸb$µ¸åÞô§8§IÝPúÚÜÅsÂCi|S¥æ[ð£Wj?–ž[z*–šŸ[j<]šLƒÏ0- ¦¶¢i`8Uˆ§ª50¤ZªX@1Ir´ÖÖY³«4€ †à×¢ÇÑà@šßWLiôH:! ’¾K$z.©é–ûd§IO…Ò׿.ž“Js·ß§5Ujºßø¼ÒbiØVü¤‚©i4 :Ó4,œ†ÆSÅ€ªQ•ƒjÊ‘ë4×Á¦ëmÕõ|Xj ~Â/ŒšÄÑÄ©ÂVû$"©é¹¤Æ[îS˜&õÚvŸJ__TJcŸ*{ ~ÅR¥sKƒ¦K#S¯3LÕ‚©I45 §JñT# Úˆ©±†W,Jbík²&WYë‡õ‚°0%ŽªÒüÎbHu¦Hun¶O+’ƽå>ÉiÒ×ù†Òx¦JmoÁår§ˆ±TýÜÒð­øÆÓ¥*Á4æhªN­Ôˆ15ÍÈ @Rl®™u×ëæAT-ŒÚŽ£:4ê©ÞVûÂóH“ˆ¤ºç’Zßrã4iA(µ=Ušì|‹±ôÕé±4;˜ÚŒ¥ÅL£DSõp=žF ©1†Uj­ˆëkµ¼NÕ£†q4å@j;’f·,ÏHà ÷Im¹·=MJ §J /vRÙ‚¯z^©òåN1ÄRÓ­øFÓ¥†Á4j4µNMªnDµT ²€4¤¼ž5]‡«¬ñUƒ¨0)ŽjR³)Ríö1ERõË›ÔÎ% Ýr᧨Ӥn(4w©JmN•š^ìdó¼ÒH±4d¾g,U8·Ôúti@0 :ÃÔ+˜Ú‹¦þáÔ,žªT[Aµ¨c+âX›¬Ñ½ÖúæQÔ;ŒÚˆ£a4¿»D ¤ºS¤~ç‘jER…íö¶.oвåÞä'ÓiÒ×­”Is—…Ò§Jý¶à‡œWšZ,õ8·Ô/–†mÅš.-˜ÆMƒÃip±4(”ZÙ‚¯p^iܱ4'˜úÅÒ°sK ¦KöãÓà3L5‚©F4U §‘ã©fDµT­GWR÷úØdͮڌ¢¨BU£¦4¿ÛøR“möªS¤aç‘æGÒì6[$5=—4Ò–{ïPêIÝP:uÞòÙa¡4Ž-øÖ.w2ޥ塱4ì’§ ­ø:=ÄÒˆÁ4Žhj#œ†ÅSíˆ!¦¦Y(&6×Ôºëy•F֌èÅ85êFÒü)Ò°­ö—6…FÒrk‘4ÒåM m¹wL·|v½©ó–Ïžµø]1¥…S¥z[ðm^îd=–FÙŠocº4–`êMm…SÝxªPCjÌq€:ÇÂÚ[g­¯ÒT¢hÔ0GÓ¤ÊS¤š[í­DRK—7EÙror“cÖâwí„RÕ©RÝ-øqÄÒì`j%–*nÅO&˜&M©V¦sIU§IÝP:mÁŠYÎ/Ä·_ÿ¼Ò¤c©ñ¹¥¶¦KU‚iÀ¥OžÁÔR4 §áñÔ, jGTËQ• ¨ ÒZÿFY³«v EýÃhô8H.i²H#DÒüóHÓŒ¤fç’FÛr`Ŭ‚Pjs ~ç•F¥ÙÁ4(–Æ9]j;˜ÆMýÃiôxZPu"ªµ Z¤Á€Xĸ†6YÓ{µ•¦`E½Ã¨õ8j;Æ>EêI½¶ÚG¤Åp.iþ–ûÂPºtuA(Me ~ ±4Ž­øiSÝhªNÍã©z@õލQbj*‘€ZÆæš;hm¯ÚÂ:ƒI £¦q4é@šÄVû"Фqm¹Ÿ½ä]™½tµ(µµ¿®ÇRéÒ¨ÁÔÆ”©i4NUâ©~DU ªq„UJ•ÊÜdm¯Ú Âúƒn5‰£ÆÓ£¯Ú ¤zS¤u=’ÚÙrïJ}b©ý-øµ'–Fž.M+˜*FÓ(á4<ž†Tˆ-¦šGVB, ¶°µÎµ¹öÖ]÷«´„°Ô2L¨JM#ÚÞj_ì‘4®-÷N- ¥š[ðkC,-–éÒÀíø†ÁÔ4šjM›æ…ÓèñT- š†ÔxÃ*¥-ê:]§ ¨4å(êF•§Fuãh„@m›}ÌS¤µ)’*n¹Ï ¥3B©íóJks,5™.µLu¦L£FÓÀpªOÕª~HµU ±€Ú.µ±é:^§„uÕ(ª55ªGU§GmÒħH‹<’šn¹wÌð ¥V·à‡]î”P,µ²?lºTo;¾õ`j)š…SÛñÔ,¢F‹©Å[HK\ëk“µ¾jG°E}è…8G UÝf6Ejc«}R‘4ìò&[[î B霥k ~3tªÔZ,]=–Ú8·4†éR“`v†ilÑÔ0œ†ÆS€ªQ£ÅÔä+u“õ¸nðj aý!¬_è„ÑXâ¨Ê¤ZÔþ©óHÍ#©ú ÷º‘4hËý쥫eÎÒ5¹¡´ –jnÁW=¯Ôf,Mo+~átiìÁTaÊÔ$šš„S+ñ4 ¢š„ÔøÂj1Hû?Š;Ò^_ÚuÝî×T{‚qÕ £ºqTwzÔv µ:Ej¸Õ>žHjñ\Ò¼PêtÑàPJ,µ0]šL05‰¦Fá4$žªT­ˆSmEÕÒ °€º.É5sØú]·¨4†°NÔ8BÃh”8š@ 4EJ$ ¥¶·àG¹Ü)öXê±_uº4­`j=šÚ§ ñT5 ‡TͰšfh Xé®§£®ßuZJ{ë¦aÔfM#ªN‘F=ÔV$µqy“ΖûÜPºðœPZci2ӥуi¤)Sh5œ*ÅSÅ€ªQ­GÕ˜â+E%¡õs”5¾jGPiAMÃ4ŒªÆQÓéQ4‘)Ò:Iç,]#3¾£JM¶à'K£^òdoºTåüR{Á4ÖhšNÃâ©r@Õˆ¨¶‚jª‘€ZÄöúÛ¤¨ö…°N‘ß5‚ˆí8W U9‡T{ŠÔÖ¥MiDÒˆ[î BéÜek ~3ÞóJ‹#–jO—FÜŽo%˜ZЦAáÔv<Õ ¨Bjq€Rfk½®Û TÚƒ(êF-ÄQ{Ôl›½îi±DÒ8Ï%uÌ]¶67”ÖêXóV|íøqSkÑ4Žp! ‡Ô˜Â*aP›¤½6 Ÿ&!Ô$ˆÚ£6âh"Ôæ©æVûÚIPúÿÅWàXãÁIEND®B`‚mfgtools-uuu_1.4.193/snap/snapcraft.yaml000066400000000000000000000074261417203213400202350ustar00rootroot00000000000000%YAML 1.1 --- # Snapcraft Recipe for uuu (Universal Update Utility) # ------------------------------ # This file is in the YAML data serialization format: # http://yaml.org # For the spec. of writing this file refer the following documentation: # * The snapcraft format # https://docs.snapcraft.io/the-snapcraft-format/8337 # * Snap Documentation # https://docs.snapcraft.io # * Topics under the doc category in the Snapcraft Forum # https://forum.snapcraft.io/c/doc # For support refer to the snapcraft section in the Snapcraft Forum: # https://forum.snapcraft.io/c/snapcraft # # Copyright (c) 2017 Snapcrafters # name: universal-update-utility title: Universal Update Utility - UUU summary: Freescale/NXP I.MX Chip image deploy tools description: | **Key features** - The real cross platform. Linux, Windows, MacOS(not test yet) - Multi devices program support - Daemon mode support - Few depedencies (only libusb, zlibc, libbz2) - Firmware (uboot/kernel) uses WCID to auto load the winusb driver on the Windows side. Windows7 users need to install the winusb driver from [https://zadig.akeo.ie/](https://zadig.akeo.ie/) Windows10 will install the driver automatically. **Search keywords** mfgtools, uuu, nxp, nxpmicro icon: snap/gui/universal-update-utility.png license: BSD-3-Clause adopt-info: main assumes: - command-chain # required by the `snapctl is-connected` command - snapd2.43 base: core18 confinement: strict grade: stable parts: # Launcher programs to fix problems at runtime launchers: source: snap/local/launchers plugin: dump organize: '*': bin/ stage: - -bin/README.* # Bash completion snippets bash-completion: source: snap/local/bash-completion plugin: dump organize: '*': bash-completion/ # Check out the tagged release revision if it isn't promoted to the stable channel # https://forum.snapcraft.io/t/selective-checkout-check-out-the-tagged-release-revision-if-it-isnt-promoted-to-the-stable-channel/10617 selective-checkout: source: https://github.com/Lin-Buo-Ren/selective-checkout.git source-tag: v2.0.2 plugin: dump build-packages: - curl - jq - sed - git stage: - scriptlets/selective-checkout prime: - -* main: after: - selective-checkout source: . source-depth: 50 override-pull: | set -o nounset snapcraftctl pull "${SNAPCRAFT_STAGE}"/scriptlets/selective-checkout \ --release-tag-pattern='uuu_[[:digit:]]+(\.[[:digit:]]+){2}' \ --release-tag-prefix=uuu_ build-snaps: - cmake build-packages: # CMake shipped in Ubuntu 18.04(3.10.2) is too old #- cmake - g++ - libbz2-dev - libusb-1.0-0-dev - libssl-dev - zlib1g-dev - pkg-config plugin: cmake stage-packages: - libbz2-1.0 - libusb-1.0-0 - libssl1.0.0 filesets: docs-copyright: - usr/share/doc/*/copyright executables: - bin/* library-shared: - lib/**/*.so* prime: - $docs-copyright - $executables - $library-shared apps: universal-update-utility: adapter: full command: bin/uuu command-chain: - bin/universal-update-utility-launch completer: bash-completion/universal-update-utility environment: # Snap runtime only ship C.UTF-8 locale LANG: C.UTF-8 LC_ALL: C.UTF-8 plugs: # Regular files access home: # Allow reading the SUDO_USER's uuu script when run as root # (by default only scripts under root's home dir is readable) read: all removable-media: # Non-A/C # NOTE: This only lifts the snapd side of confinement, the user still # require classic read/write access to the target device node raw-usb: network-bind: mfgtools-uuu_1.4.193/uuu/000077500000000000000000000000001417203213400152345ustar00rootroot00000000000000mfgtools-uuu_1.4.193/uuu/CMakeLists.txt000066400000000000000000000034751417203213400200050ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.4) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_SKIP_RPATH ON) find_package(PkgConfig REQUIRED) pkg_check_modules(LIBUSB REQUIRED libusb-1.0>=1.0.16) pkg_check_modules(LIBZ REQUIRED zlib) find_package(Threads) if (STATIC) set(OPENSSL_USE_STATIC_LIBS TRUE) endif() find_package(OpenSSL) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -O2") if (STATIC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++ -static-libgcc") endif() set(LSTS uuu.lst emmc_burn_loader.lst emmc_burn_all.lst fat_write.lst qspi_burn_loader.lst sd_burn_loader.lst spl_boot.lst sd_burn_all.lst nand_burn_loader.lst ) link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libuuu ${LIBUSB_LIBRARY_DIRS} ${LIBZ_LIBRARY_DIRS}) set(CLIST_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/gen_txt_include.sh) set(generated_files_dir "${CMAKE_BINARY_DIR}/uuu/gen") function(preprocess_clst out_var) set(result) foreach(in_f ${ARGN}) set(out_f "${generated_files_dir}/${in_f}") string(REPLACE ".lst" ".clst" out_f ${out_f}) add_custom_command(OUTPUT ${out_f} PRE_BUILD COMMAND mkdir -p ${generated_files_dir} COMMAND ${CLIST_EXECUTABLE} ${in_f} ${out_f} DEPENDS ${in_f} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Creating preprocessed clst file ${out_f}" VERBATIM ) list(APPEND result ${out_f}) endforeach() set(${out_var} "${result}" PARENT_SCOPE) endfunction() preprocess_clst(CLSTS ${LSTS}) include_directories(${generated_files_dir}) set(SOURCES uuu.cpp buildincmd.cpp autocomplete.cpp ${CLSTS} ) add_executable(uuu ${SOURCES}) target_link_libraries(uuu uuc_s ${OPENSSL_LIBRARIES} ${LIBUSB_LIBRARIES} ${LIBZ_LIBRARIES} dl bz2) install(TARGETS uuu DESTINATION bin) target_compile_definitions(uuu PRIVATE "TARGET_PATH=\"${CMAKE_INSTALL_PREFIX}/bin/uuu\"" ) mfgtools-uuu_1.4.193/uuu/autocomplete.cpp000066400000000000000000000124021417203213400204400ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "buildincmd.h" #include "../libuuu/libuuu.h" #ifndef _MSC_VER #include #include #else #include #endif using namespace std; void linux_auto_arg(const char *space = " ", const char * filter = "") { string str = filter; const char *param[] = { "-b", "-d", "-v", "-V", "-s", NULL }; int i = 0; for (int i = 0; param[i]; i++) { if (str.find(param[i]) == string::npos) cout << param[i] << space << endl; } } int linux_autocomplete_ls(const char *path, void *p) { cout << path + 2 << endl; return 0; } void linux_autocomplete(int argc, char **argv) { string last; string cur; if (argc == 3) { last = argv[2]; }else { cur = argv[2]; last = argv[3]; } if (cur[0] == '-') { if (cur.size() == 1) linux_auto_arg(); else cout << cur << " " << endl; return; } if (last.size()>=3) { if (last.substr(last.size() - 3) == "uuu" &&(cur.empty() || cur[0] == '-')) { linux_auto_arg(); cout << cur << endl; } }else if(last.empty()) { linux_auto_arg(); } else if (last == "-b") { return g_BuildScripts.PrintAutoComplete(cur); }else if(last[0] == '-') { linux_auto_arg(); } uuu_for_each_ls_file(linux_autocomplete_ls, cur.c_str(), NULL); } string get_next_word(string str, size_t &pos) { size_t start = 0; start = str.find(' ', pos); string sub = str.substr(pos, start - pos); pos = start == string::npos ? start : start + 1; return sub; } void power_shell_autocomplete(const char *p) { string pstr = p; size_t pos = 0; string file; vector argv; string params; while (pos != string::npos && pos < pstr.size()) { file = get_next_word(pstr, pos); argv.push_back(file); if (file.size() && file[0] == '-') params += " " + file; } string last = argv[argv.size() - 1]; string prev = argv.size() > 1 ? argv[argv.size() - 2] : ""; if (last == "-b" || prev == "-b") { string cur; if (prev == "-b") cur = last; if (g_BuildScripts.find(cur) == g_BuildScripts.end()) g_BuildScripts.PrintAutoComplete(cur, ""); last.clear(); } else { if (last[0] == '-' || argv.size() == 1) linux_auto_arg("", params.c_str()); } if (argv.size() == 1) last.clear(); uuu_for_each_ls_file(linux_autocomplete_ls, last.c_str(), NULL); } int auto_complete(int argc, char**argv) { if (argc == 4 || argc == 3) { string str = argv[1]; if (str.size() >= 3) if (str.substr(str.size() - 3) == "uuu") { linux_autocomplete(argc, argv); return 0; } } if (argc >= 2) { string str = argv[1]; if (str == "-autocomplete") { power_shell_autocomplete(argc == 2 ? "" : argv[2]); return 0; } } return 1; } void print_autocomplete_help() { #ifndef _MSC_VER { cout << "Enjoy auto [tab] command complete by put below script into /etc/bash_completion.d/uuu" << endl; cout << g_vt_kcyn; cout << " _uuu_autocomplete()" < #include #include static std::string replace_str(std::string str, std::string key, std::string replace); static std::string str_to_upper(const std::string &str); /** * @brief Parse characters between argument name and its description and check * if its an optional one * @param[in] option The characters between argument name and its description to * be parsed * @return `0` in any case */ void BuiltInScript::Arg::parser(const std::string &option) { const auto pos = option.find('['); if (pos == std::string::npos) { return; } m_fallback_option = option.substr(pos + 1, option.find(']') - pos - 1); m_flags = ARG_OPTION | ARG_OPTION_KEY; } /** * @brief Create a new BuiltInScript instance by extracting information from a * BuiltInScriptRawData instance * @param[in] p The BuiltInScriptRawData containing all data of the script this * BuiltInScript instance shall represent */ BuiltInScript::BuiltInScript(const BuiltInScriptRawData * const p) : m_text{p->m_text}, m_desc{p->m_desc ? p->m_desc : ""}, m_name{p->m_name ? p->m_name : ""} { // Regular expression to detect script argument name occurrences static const std::regex arg_name_regexp{R"####((@| )(_\S+))####"}; for (std::sregex_iterator it = std::sregex_iterator{m_text.cbegin(), m_text.cend(), arg_name_regexp}; it != std::sregex_iterator{}; ++it) { const std::string param{it->str(2)}; if (!find_args(param)) { Arg a; a.m_name = param; a.m_flags = Arg::ARG_MUST; m_args.emplace_back(std::move(a)); } } for (size_t i = 0; i < m_args.size(); i++) { std::string str; str += "@"; str += m_args[i].m_name; const auto pos = m_text.find(str); if (pos != std::string::npos) { const auto start_descript = m_text.find('|', pos); if (start_descript != std::string::npos) { m_args[i].m_desc = m_text.substr(start_descript + 1, m_text.find('\n', start_descript) - start_descript - 1); const std::string def{m_text.substr(pos, start_descript - pos)}; m_args[i].parser(def); } } } } /** * @brief Check if the BuiltInScript instance has an argument called `arg` * @param[in] arg The argument for which its existence in the BuiltInScript * shall be checked * @return `true` if BuiltInScript has an argument named `arg`, `false` * otherwise */ bool BuiltInScript::find_args(const std::string &arg) const { return std::any_of(m_args.cbegin(), m_args.cend(), [&arg](const Arg &brg){ return brg.m_name == arg; }); } /** * @brief Replace built-in script's arguments by actual values given in `args` * @param[in] args The actual values that shall replace the arguments (the order * must fit the order of the arguments in the script) * @return A copy of the built-in script with the arguments replaced by their * actual values */ std::string BuiltInScript::replace_script_args(const std::vector &args) const { std::string script = m_text; for (size_t i = 0; i < args.size() && i < m_args.size(); i++) { script = replace_str(script, m_args[i].m_name, args[i]); } //handle option args; for (size_t i = args.size(); i < m_args.size(); i++) { if (m_args[i].m_flags & Arg::ARG_OPTION_KEY) { for (size_t j = 0; j < args.size(); j++) { if (m_args[j].m_name == m_args[i].m_fallback_option) { script = replace_str(script, m_args[i].m_name, args[j]); break; } } } } return script; } /** * @brief Print the built-in script to `stdout` followed by a newline */ void BuiltInScript::show() const { printf("%s\n", m_text.c_str()); } /** * @brief Print the script's name, its description and its arguments to stdout */ void BuiltInScript::show_cmd() const { printf("\t%s%s%s\t%s\n", g_vt_boldwhite, m_name.c_str(), g_vt_default, m_desc.c_str()); for (auto i = 0u; i < m_args.size(); ++i) { std::string desc{m_args[i].m_name}; if (m_args[i].m_flags & Arg::ARG_OPTION) { desc += g_vt_boldwhite; desc += "[Optional]"; desc += g_vt_default; } desc += " "; desc += m_args[i].m_desc; printf("\t\targ%u: %s\n", i, desc.c_str()); } } /** * @brief Create a new map by parsing an array of BuiltInScriptRawData instances * @param[in] p Pointer to the first element of a BuiltInScriptRawData array */ BuiltInScriptMap::BuiltInScriptMap(const BuiltInScriptRawData*p) { while (p->m_name) { emplace(p->m_name, p); ++p; } } /** * @brief Auto-complete names of built-in scripts if they match `match` * @param[in] match The string against which the scripts' names will be machted * @param[in] space A separator character which shall be printed after the * completed script name */ void BuiltInScriptMap::PrintAutoComplete(const std::string &match, const char *space) const { for (const auto &script_pair : *this) { if(script_pair.first.substr(0, match.size()) == match) { printf("%s%s\n", script_pair.first.c_str(), space); } } } /** * @brief Print information about all contained scripts to stdout */ void BuiltInScriptMap::ShowAll() const { for (const auto &script_pair : *this) { script_pair.second.show_cmd(); } } /** * @brief Print the names of all contained scripts to the given stream * @param[in] file The stream to which the names shall be printed */ void BuiltInScriptMap::ShowCmds(FILE * const file) const { fprintf(file, "<"); for (auto iCol = begin(); iCol != end(); ++iCol) { fprintf(file, "%s", iCol->first.c_str()); auto i = iCol; i++; if(i != end()) { fprintf(file, "|"); } } fprintf(file, ">"); } /** * @brief Replace a `key` substring of a string `str` by a replacement `replace` * @param[in] str The string of which a copy with the replacements shall be * created * @param[in] key The string which shall be replaced * @param[in] replace The string that shall replace ocurrences of `key` * @return A new string instance with the replacements conducted on it */ static std::string replace_str(std::string str, std::string key, std::string replace) { if (replace.size() > 4) { if (replace[replace.size() - 1] == '\"') { if (str_to_upper(replace.substr(replace.size() - 5)) == ".BZ2\"") { replace = replace.substr(0, replace.size() - 1); replace += "/*\""; } }else if (str_to_upper(replace.substr(replace.size() - 4)) == ".BZ2") { replace += "/*"; } } for (size_t j = 0; (j = str.find(key, j)) != std::string::npos;) { if (j == 0 || (j!=0 && str[j - 1] == ' ')) str.replace(j, key.size(), replace); j += key.size(); } return str; } /** * @brief Returns a copy of `str` with all applicable characters converted to * uppercase * @param[in] str The string for which an uppercase copy shall be created * @return The copy of `str` converted to uppercase */ static std::string str_to_upper(const std::string &str) { const std::locale loc; std::string s; s.reserve(str.size()); for (size_t i = 0; i < str.size(); ++i) { s.push_back(std::toupper(str[i], loc)); } return s; } //! Array containing raw information about all the built-in scripts of uuu static constexpr BuiltInScriptRawData g_builtin_cmd[] = { { "emmc", #include "emmc_burn_loader.clst" ,"burn boot loader to eMMC boot partition" }, { "emmc_all", #include "emmc_burn_all.clst" ,"burn whole image to eMMC" }, { "fat_write", #include "fat_write.clst" ,"update one file in fat partition, require uboot fastboot running in board" }, { "nand", #include "nand_burn_loader.clst" ,"burn boot loader to NAND flash" }, { "qspi", #include "qspi_burn_loader.clst" ,"burn boot loader to qspi nor flash" }, { "sd", #include "sd_burn_loader.clst" ,"burn boot loader to sd card" }, { "sd_all", #include "sd_burn_all.clst" ,"burn whole image to sd card" }, { "spl", #include "spl_boot.clst" ,"boot spl and uboot" }, { nullptr, nullptr, nullptr, } }; //! A map of the built-in scripts' names to their BuiltInScript representations BuiltInScriptMap g_BuildScripts(g_builtin_cmd); mfgtools-uuu_1.4.193/uuu/buildincmd.h000066400000000000000000000073641417203213400175310ustar00rootroot00000000000000/* * Copyright 2018-2021 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include #include #include extern const char * g_vt_boldwhite; extern const char * g_vt_default; extern const char * g_vt_kcyn; extern const char * g_vt_green; extern const char * g_vt_red ; extern const char * g_vt_yellow; /** * @brief Structure to hold the raw data of a built-in script */ struct BuiltInScriptRawData { //! The name of the built-in script const char * const m_name = nullptr; //! The actual built-in script itself const char * const m_text = nullptr; //! A description of the built-in script's purpose const char * const m_desc = nullptr; }; class BuiltInScript { public: /** * @brief A class for representing arguments of built-in scripts represented * by BuiltInScript */ class Arg { public: enum { ARG_MUST = 0x1, ARG_OPTION = 0x2, ARG_OPTION_KEY = 0x4, }; void parser(const std::string &option); //! The name of the argument std::string m_name; //! A description of the argument std::string m_desc; //! Flags of the argument (basically if it's optional or not) uint32_t m_flags = ARG_MUST; //! The argument whose value this one will fall back to if it's optional //! and not given explicitly std::string m_fallback_option; }; BuiltInScript() {}; BuiltInScript(const BuiltInScriptRawData*p); std::string replace_script_args(const std::vector &args) const; void show() const; void show_cmd() const; //! The actual script which is being represented const std::string m_text; //! A description of the script's purpose const std::string m_desc; //! A short name of the built-in script const std::string m_name; //! The arguments of the built-in script std::vector m_args; private: bool find_args(const std::string &arg) const; }; /** * @brief A map of all built-in scripts indexed by their names * * Each built-in script is represented by a BuiltInScript instance. */ class BuiltInScriptMap : public std::map { public: BuiltInScriptMap(const BuiltInScriptRawData*p); void PrintAutoComplete(const std::string &match, const char *space = " ") const; void ShowAll() const; void ShowCmds(FILE * file=stdout) const; }; //! A map of the built-in scripts' names to their BuiltInScript representations extern BuiltInScriptMap g_BuildScripts; mfgtools-uuu_1.4.193/uuu/emmc_burn_all.lst000066400000000000000000000022101417203213400205520ustar00rootroot00000000000000uuu_version 1.4.149 # @_flash.bin | bootloader, which can extract from wic image # @_image [_flash.bin] | wic image burn to emmc. # This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ SDP: boot -f _flash.bin -scanlimited 0x800000 # This command will be run when ROM support stream mode # i.MX8QXP, i.MX8QM SDPS: boot -scanterm -f _flash.bin -scanlimited 0x800000 # These commands will be run when use SPL and will be skipped if no spl # SDPU will be deprecated. please use SDPV instead of SDPU # { SDPU: delay 1000 SDPU: write -f _flash.bin -offset 0x57c00 SDPU: jump -scanlimited 0x800000 # } # These commands will be run when use SPL and will be skipped if no spl # if (SPL support SDPV) # { SDPV: delay 1000 SDPV: write -f _flash.bin -skipspl -scanterm -scanlimited 0x800000 SDPV: jump -scanlimited 0x800000 # } FB: ucmd setenv fastboot_dev mmc FB: ucmd setenv mmcdev ${emmc_dev} FB: ucmd mmc dev ${emmc_dev} FB: flash -raw2sparse all _image FB: flash -scanterm -scanlimited 0x800000 bootloader _flash.bin FB: ucmd if env exists emmc_ack; then ; else setenv emmc_ack 0; fi; FB: ucmd mmc partconf ${emmc_dev} ${emmc_ack} 1 0 FB: done mfgtools-uuu_1.4.193/uuu/emmc_burn_loader.lst000066400000000000000000000016721417203213400212630ustar00rootroot00000000000000uuu_version 1.2.39 # @_flash.bin | bootloader # @_image [_flash.bin] | image burn to emmc, default is the same as bootloader # This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ SDP: boot -f _flash.bin # This command will be run when ROM support stream mode # i.MX8QXP, i.MX8QM SDPS: boot -f _flash.bin # These commands will be run when use SPL and will be skipped if no spl # SDPU will be deprecated. please use SDPV instead of SDPU # { SDPU: delay 1000 SDPU: write -f _flash.bin -offset 0x57c00 SDPU: jump # } # These commands will be run when use SPL and will be skipped if no spl # if (SPL support SDPV) # { SDPV: delay 1000 SDPV: write -f _flash.bin -skipspl SDPV: jump # } FB: ucmd setenv fastboot_dev mmc FB: ucmd setenv mmcdev ${emmc_dev} FB: ucmd mmc dev ${emmc_dev} FB: flash bootloader _image FB: ucmd if env exists emmc_ack; then ; else setenv emmc_ack 0; fi; FB: ucmd mmc partconf ${emmc_dev} ${emmc_ack} 1 0 FB: Done mfgtools-uuu_1.4.193/uuu/fat_write.lst000066400000000000000000000010061417203213400177410ustar00rootroot00000000000000uuu_version 1.1.4 # @_image | image, which cp to fat partition # @_device | storage device, mmc\sata # @_partition | fat partition number, like 1:1 # @_filename [_image] | file name in target fat partition, only support rootdir now FB: ucmd setenv fastboot_buffer ${loadaddr} FB: download -f _image FB: ucmd if test ! -n "$fastboot_bytes"; then setenv fastboot_bytes $filesize; else true; fi FB[-t 20000]: ucmd fatwrite _device _partition ${fastboot_buffer} _filename ${fastboot_bytes} FB: done mfgtools-uuu_1.4.193/uuu/gen_txt_include.sh000077500000000000000000000001021417203213400207370ustar00rootroot00000000000000#!/bin/sh echo "R\"####(" > $2 cat $1 >> $2 echo ")####\"" >> $2 mfgtools-uuu_1.4.193/uuu/nand_burn_loader.lst000066400000000000000000000021421417203213400212530ustar00rootroot00000000000000uuu_version 1.2.39 # @_flash.bin | bootloader # @_image [_flash.bin] | image burn to nand, default is the same as bootloader # This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ SDP: boot -f _flash.bin # This command will be run when ROM support stream mode # i.MX8QXP, i.MX8QM SDPS: boot -f _flash.bin # These commands will be run when use SPL and will be skipped if no spl # SDPU will be deprecated. please use SDPV instead of SDPU # { SDPU: delay 1000 SDPU: write -f _flash.bin -offset 0x57c00 SDPU: jump # } # These commands will be run when use SPL and will be skipped if no spl # if (SPL support SDPV) # { SDPV: delay 1000 SDPV: write -f _flash.bin -skipspl SDPV: jump # } FB: ucmd setenv fastboot_buffer ${loadaddr} FB: download -f _image FB: ucmd if test ! -n "$fastboot_bytes"; then setenv fastboot_bytes $filesize; else true; fi # Burn image to nandfit partition if needed FB: ucmd if env exists nandfit_part; then nand erase.part nandfit; nand write ${fastboot_buffer} nandfit ${fastboot_bytes}; else true; fi; FB: ucmd nandbcb init ${fastboot_buffer} nandboot ${fastboot_bytes} FB: Done mfgtools-uuu_1.4.193/uuu/qspi_burn_loader.lst000066400000000000000000000031351417203213400213120ustar00rootroot00000000000000uuu_version 1.2.39 # @_flexspi.bin | bootloader # @_image [_flexspi.bin] | image burn to flexspi, default is the same as bootloader # This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ SDP: boot -f _flexspi.bin # This command will be run when ROM support stream mode # i.MX8QXP, i.MX8QM, skip QSPI header SDPS: boot -f _flexspi.bin -skipfhdr # These commands will be run when use SPL and will be skipped if no spl # SDPU will be deprecated. please use SDPV instead of SDPU # { SDPU: delay 1000 SDPU: write -f _flexspi.bin -offset 0x10000 -skipfhdr SDPU: jump # } # These commands will be run when use SPL and will be skipped if no spl # if (SPL support SDPV) # { SDPV: delay 1000 SDPV: write -f _flexspi.bin -skipspl -skipfhdr SDPV: jump # } FB: ucmd setenv fastboot_buffer ${loadaddr} FB: download -f _image FB: ucmd if test ! -n "$fastboot_bytes"; then setenv fastboot_bytes $filesize; else true; fi # Check Image if include flexspi header FB: ucmd if qspihdr dump ${fastboot_buffer}; then setenv qspihdr_exist yes; else setenv qspihdr_exist no; fi; FB[-t 60000]: ucmd if test ${qspihdr_exist} = yes; then qspihdr init ${fastboot_buffer} ${fastboot_bytes} safe; else true; fi; #if uboot can't support qspihdr command, use uboot image to write qspi image, which require image include qspi flash header FB: ucmd if test ${qspihdr_exist} = no; then sf probe; else true; fi; FB[-t 40000]: ucmd if test ${qspihdr_exist} = no; then sf erase 0 +${fastboot_bytes}; else true; fi; FB[-t 20000]: ucmd if test ${qspihdr_exist} = no; then sf write ${fastboot_buffer} 0 ${fastboot_bytes}; else true; fi; FB: done mfgtools-uuu_1.4.193/uuu/sd_burn_all.lst000066400000000000000000000020431417203213400202430ustar00rootroot00000000000000uuu_version 1.4.149 # @_flash.bin | bootloader, which can extract from wic image # @_image [_flash.bin] | wic image burn to emmc. # This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ SDP: boot -f _flash.bin -scanlimited 0x800000 # This command will be run when ROM support stream mode # i.MX8QXP, i.MX8QM SDPS: boot -scanterm -f _flash.bin -scanlimited 0x800000 # These commands will be run when use SPL and will be skipped if no spl # SDPU will be deprecated. please use SDPV instead of SDPU # { SDPU: delay 1000 SDPU: write -f _flash.bin -offset 0x57c00 -scanlimited 0x800000 SDPU: jump -scanlimited 0x800000 # } # These commands will be run when use SPL and will be skipped if no spl # if (SPL support SDPV) # { SDPV: delay 1000 SDPV: write -f _flash.bin -skipspl -scanterm -scanlimited 0x800000 SDPV: jump -scanlimited 0x800000 # } FB: ucmd setenv fastboot_dev mmc FB: ucmd setenv mmcdev ${sd_dev} FB: ucmd mmc dev ${sd_dev} FB: flash -raw2sparse all _image FB: flash -scanterm -scanlimited 0x800000 bootloader _flash.bin FB: done mfgtools-uuu_1.4.193/uuu/sd_burn_loader.lst000066400000000000000000000015001417203213400207360ustar00rootroot00000000000000uuu_version 1.2.39 # @_flash.bin | bootloader # @_image [_flash.bin] | image burn to emmc, default is the same as bootloader # This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ SDP: boot -f _flash.bin # This command will be run when ROM support stream mode # i.MX8QXP, i.MX8QM SDPS: boot -f _flash.bin # These commands will be run when use SPL and will be skipped if no spl # SDPU will be deprecated. please use SDPV instead of SDPU # { SDPU: delay 1000 SDPU: write -f _flash.bin -offset 0x57c00 SDPU: jump # } # These commands will be run when use SPL and will be skipped if no spl # if (SPL support SDPV) # { SDPV: delay 1000 SDPV: write -f _flash.bin -skipspl SDPV: jump # } FB: ucmd setenv fastboot_dev mmc FB: ucmd setenv mmcdev ${sd_dev} FB: ucmd mmc dev ${sd_dev} FB: flash bootloader _image FB: Done mfgtools-uuu_1.4.193/uuu/spl_boot.lst000066400000000000000000000011321417203213400175760ustar00rootroot00000000000000uuu_version 1.2.39 # This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ SDP: boot -f _flash.bin # This command will be run when ROM support stream mode # i.MX8QXP, i.MX8QM SDPS: boot -f _flash.bin # These commands will be run when use SPL and will be skipped if no spl # SDPU will be deprecated. please use SDPV instead of SDPU # { SDPU: delay 1000 SDPU: write -f _flash.bin -offset 0x57c00 SDPU: jump SDPU: done # } # These commands will be run when use SPL and will be skipped if no spl # if (SPL support SDPV) # { SDPV: delay 1000 SDPV: write -f _flash.bin -skipspl SDPV: jump SDPV: done # }mfgtools-uuu_1.4.193/uuu/uuu.cpp000066400000000000000000000604401417203213400165620ustar00rootroot00000000000000/* * Copyright 2018 NXP. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of the NXP Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "buildincmd.h" #include #include #include "../libuuu/libuuu.h" const char * g_vt_yellow = "\x1B[93m"; const char * g_vt_default = "\x1B[0m"; const char * g_vt_green = "\x1B[92m"; const char * g_vt_red = "\x1B[91m"; const char * g_vt_kcyn = "\x1B[36m"; const char * g_vt_boldwhite = "\x1B[97m"; void clean_vt_color() noexcept { g_vt_yellow = ""; g_vt_default = g_vt_yellow; g_vt_green = g_vt_yellow; g_vt_red = g_vt_yellow; g_vt_kcyn = g_vt_yellow; g_vt_boldwhite = g_vt_yellow; } using namespace std; int get_console_width(); void print_oneline(string str); int auto_complete(int argc, char**argv); void print_autocomplete_help(); char g_sample_cmd_list[] = { #include "uuu.clst" }; vector g_usb_path_filter; int g_verbose = 0; static bool g_start_usb_transfer; class AutoCursor { public: ~AutoCursor() { printf("\x1b[?25h\n\n\n"); } }; void ctrl_c_handle(int) { do { AutoCursor a; } while(0); exit(1); } class string_ex : public std::string { public: int format(const char *fmt, ...) { va_list args; va_start(args, fmt); size_t len = std::vsnprintf(NULL, 0, fmt, args); va_end(args); this->resize(len); va_start(args, fmt); std::vsnprintf((char*)c_str(), len + 1, fmt, args); va_end(args); return 0; } }; void print_help(bool detail = false) { const char help[] = "uuu [-d -m -v -V] <" "bootloader|cmdlists|cmd" ">\n\n" " bootloader download bootloader to board by usb\n" " cmdlist run all commands in cmdlist file\n" " If it is path, search uuu.auto in dir\n" " If it is zip, search uuu.auto in zip\n" " cmd Run one command, use -H see detail\n" " example: SDPS: boot -f flash.bin\n" " -d Daemon mode, wait for forever.\n" " -v -V verbose mode, -V enable libusb error\\warning info\n" " -dry Dry run mode, check if script or cmd correct \n" " -m USBPATH Only monitor these paths.\n" " -m 1:2 -m 1:3\n\n" " -t Timeout second for wait known usb device appeared\n" " -T Timeout second for wait next known usb device appeared at stage switch\n" " -e set environment variable key=value\n" " -pp usb polling period in milliseconds\n" "uuu -s Enter shell mode. uuu.inputlog record all input commands\n" " you can use \"uuu uuu.inputlog\" next time to run all commands\n\n" "uuu -udev linux: show udev rule to avoid sudo each time \n" "uuu -lsusb List connected know devices\n" "uuu -IgSerNum Set windows registry to ignore USB serial number for known uuu devices\n" "uuu -h show general help\n" "uuu -H show general help and detailed help for commands\n\n"; printf("%s", help); printf("uuu [-d -m -v] -b[run] "); g_BuildScripts.ShowCmds(); printf(" arg...\n"); printf("\tRun Built-in scripts\n"); g_BuildScripts.ShowAll(); printf("\nuuu -bshow "); g_BuildScripts.ShowCmds(); printf("\n"); printf("\tShow built-in script\n"); printf("\n"); print_autocomplete_help(); if (detail == false) return; size_t start = 0, pos = 0; string str= g_sample_cmd_list; bool bprint = false; while ((pos = str.find('\n',pos)) != str.npos) { string s = str.substr(start, pos - start); if (s.substr(0, 6) == "# ----") bprint = true; if (bprint) { if (s[0] == '#') { printf("%s\n", &(s[1])); } } pos += 1; start = pos; } } void print_version() { printf("uuu (Universal Update Utility) for nxp imx chips -- %s\n\n", uuu_get_version_string()); } int print_cfg(const char *pro, const char * chip, const char * /*compatible*/, uint16_t pid, uint16_t vid, uint16_t bcdmin, uint16_t bcdmax, void * /*p*/) { const char *ext; if (strlen(chip) >= 7) ext = ""; else ext = "\t"; if (bcdmin == 0 && bcdmax == 0xFFFF) printf("\t%s\t %s\t%s 0x%04x\t 0x%04x\n", pro, chip, ext, pid, vid); else printf("\t%s\t %s\t%s 0x%04x\t 0x%04x\t [0x%04x..0x%04x]\n", pro, chip, ext, pid, vid, bcdmin, bcdmax); return 0; } int print_udev_rule(const char * /*pro*/, const char * /*chip*/, const char * /*compatible*/, uint16_t vid, uint16_t pid, uint16_t /*bcdmin*/, uint16_t /*bcdmax*/, void * /*p*/) { printf("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", TAG+=\"uaccess\"\n", vid, pid); return 0; } int polling_usb(std::atomic& bexit); int g_overall_status; int g_overall_okay; int g_overall_failure; char g_wait[] = "|/-\\"; int g_wait_index; string build_process_bar(size_t width, size_t pos, size_t total) { string str; str.resize(width, ' '); str[0] = '['; str[width - 1] = ']'; if (total == 0) { if (pos == 0) return str; string_ex loc; size_t s = pos / (1024 * 1024); loc.format("%dM", s); str.replace(1, loc.size(), loc); return str; } size_t i; if (pos > total) pos = total; for (i = 1; i < (width-2) * pos / total; i++) { str[i] = '='; } if (i > 1) str[i] = '>'; if (pos == total) str[str.size() - 2] = '='; string_ex per; per.format("%d%%", pos * 100 / total); size_t start = (width - per.size()) / 2; str.replace(start, per.size(), per); str.insert(start, g_vt_yellow); str.insert(start + per.size() + strlen(g_vt_yellow), g_vt_default); return str; } void print_auto_scroll(string str, size_t len, size_t start) { if (str.size() <= len) { str.resize(len, ' '); cout << str; return; } if(str.size()) start = start % str.size(); else start = 0; string s = str.substr(start, len); s.resize(len, ' '); cout << s; } class ShowNotify { public: string m_cmd; string m_dev; size_t m_trans_pos = 0; int m_status = 0; size_t m_cmd_total = 0; size_t m_cmd_index = 0; string m_last_err; int m_done = 0; size_t m_start_pos = 0; size_t m_trans_size = 0; clock_t m_start_time; uint64_t m_cmd_start_time; uint64_t m_cmd_end_time; bool m_IsEmptyLine = false; ShowNotify() : m_start_time{clock()} {} bool update(uuu_notify nt) { if (nt.type == uuu_notify::NOFITY_DEV_ATTACH) { m_dev = nt.str; m_done = 0; m_status = 0; } if (nt.type == uuu_notify::NOTIFY_CMD_START) { m_start_pos = 0; m_cmd = nt.str; m_cmd_start_time = nt.timestamp; } if (nt.type == uuu_notify::NOTIFY_DECOMPRESS_START) { m_start_pos = 0; m_cmd = nt.str; m_cmd_start_time = nt.timestamp; m_dev = "Prep"; } if (nt.type == uuu_notify::NOTIFY_DOWNLOAD_START) { m_start_pos = 0; m_cmd = nt.str; m_cmd_start_time = nt.timestamp; m_dev = "Prep"; } if (nt.type == uuu_notify::NOTIFY_DOWNLOAD_END) { m_IsEmptyLine = true; } if (nt.type == uuu_notify::NOTIFY_TRANS_SIZE || nt.type == uuu_notify::NOTIFY_DECOMPRESS_SIZE) { m_trans_size = nt.total; return false; } if (nt.type == uuu_notify::NOTIFY_CMD_TOTAL) { m_cmd_total = nt.total; return false; } if (nt.type == uuu_notify::NOTIFY_CMD_INDEX) { m_cmd_index = nt.index; return false; } if (nt.type == uuu_notify::NOTIFY_DONE) { if (m_status) g_overall_failure++; else g_overall_okay++; m_done = 1; } if (nt.type == uuu_notify::NOTIFY_CMD_END) { m_cmd_end_time = nt.timestamp; if(nt.status) { g_overall_status = nt.status; m_last_err = uuu_get_last_err_string(); } m_status |= nt.status; if (m_status) g_overall_failure++; } if (nt.type == uuu_notify::NOTIFY_TRANS_POS || nt.type == uuu_notify::NOTIFY_DECOMPRESS_POS) { if (m_trans_size == 0) { m_trans_pos = nt.index; return true; } if ((nt.index - m_trans_pos) < (m_trans_size / 100) && nt.index != m_trans_size) return false; m_trans_pos = nt.index; } return true; } void print_verbose(uuu_notify*nt) { if (this->m_dev == "Prep" && g_start_usb_transfer) return; if (nt->type == uuu_notify::NOFITY_DEV_ATTACH) { cout << "New USB Device Attached at " << nt->str << endl; } if (nt->type == uuu_notify::NOTIFY_CMD_START) { cout << m_dev << ">" << "Start Cmd:" << nt->str << endl; } if (nt->type == uuu_notify::NOTIFY_CMD_END) { double diff = m_cmd_end_time - m_cmd_start_time; diff /= 1000; if (nt->status) { cout << m_dev << ">" << g_vt_red <<"Fail " << uuu_get_last_err_string() << "("<< std::setprecision(4) << diff << "s)" << g_vt_default << endl; } else { cout << m_dev << ">" << g_vt_green << "Okay ("<< std::setprecision(4) << diff << "s)" << g_vt_default << endl; } } if (nt->type == uuu_notify::NOTIFY_TRANS_POS || nt->type == uuu_notify::NOTIFY_DECOMPRESS_POS) { if (m_trans_size) cout << g_vt_yellow << "\r" << m_trans_pos * 100 / m_trans_size <<"%" << g_vt_default; else cout << "\r" << m_trans_pos; cout.flush(); } if (nt->type == uuu_notify::NOTIFY_CMD_INFO) cout << nt->str; if (nt->type == uuu_notify::NOTIFY_WAIT_FOR) cout << "\r" << nt->str << " "<< g_wait[((g_wait_index++) & 0x3)]; if (nt->type == uuu_notify::NOTIFY_DECOMPRESS_START) cout << "Decompress file:" << nt->str << endl; if (nt->type == uuu_notify::NOTIFY_DOWNLOAD_START) cout << "Download file:" << nt->str << endl; } void print(int verbose = 0, uuu_notify*nt=NULL) { verbose ? print_verbose(nt) : print_simple(); } string get_print_dev_string() { string str; str = m_dev; str.resize(8, ' '); string_ex s; s.format("%2d/%2d", m_cmd_index+1, m_cmd_total); str += s; return str; } void print_simple() { int width = get_console_width(); int info, bar; info = 14; bar = 40; if (m_IsEmptyLine) { string str(width, ' '); cout << str; return; } if (width <= bar + info + 3) { string_ex str; str += get_print_dev_string(); str += g_wait[(g_wait_index++) & 0x3]; print_oneline(str); return ; } else { string_ex str; str += get_print_dev_string(); str.resize(info, ' '); cout << str; if (m_done || m_status) { string str; str.resize(bar, ' '); str[0] = '['; str[str.size() - 1] = ']'; string err; if (m_status) { err = uuu_get_last_err_string(); err.resize(bar - 2, ' '); str.replace(1, err.size(), err); str.insert(1, g_vt_red); str.insert(1 + strlen(g_vt_red) + err.size(), g_vt_default); } else { str.replace(1, 4, "Done"); str.insert(1, g_vt_green); str.insert(1 + strlen(g_vt_green) + strlen("Done"), g_vt_default); } cout << str; } else { cout << build_process_bar(bar, m_trans_pos, m_trans_size); } cout << " "; print_auto_scroll(m_cmd, width - bar - info-1, m_start_pos); if (clock() - m_start_time > CLOCKS_PER_SEC / 4) { m_start_pos++; m_start_time = clock(); } cout << endl; return; } } }; static map g_map_path_nt; mutex g_callback_mutex; void print_oneline(string str) { size_t w = get_console_width(); if (w <= 3) return; if (str.size() >= w) { str.resize(w - 1); str[str.size() - 1] = '.'; str[str.size() - 2] = '.'; str[str.size() - 3] = '.'; } else { str.resize(w, ' '); } cout << str << endl; } ShowNotify Summary(map *np) { ShowNotify sn; for (auto it = np->begin(); it != np->end(); it++) { if (it->second.m_dev == "Prep") { sn.m_trans_size += it->second.m_trans_size; sn.m_trans_pos += it->second.m_trans_pos; } else { if (it->second.m_trans_pos || it->second.m_cmd_index) g_start_usb_transfer = true; // Hidden HTTP download when USB start transfer } } if(g_start_usb_transfer) sn.m_IsEmptyLine = true; // Hidden HTTP download when USB start transfer sn.m_dev = "Prep"; sn.m_cmd = "Http Download\\Uncompress"; return sn; } int progress(uuu_notify nt, void *p) { map *np = (map*)p; map::iterator it; std::lock_guard lock(g_callback_mutex); if ((*np)[nt.id].update(nt)) { if (!(*np)[nt.id].m_dev.empty()) if ((*np)[nt.id].m_dev != "Prep") g_map_path_nt[(*np)[nt.id].m_dev] = (*np)[nt.id]; if (g_verbose) { if((*np)[nt.id].m_dev == "Prep") Summary(np).print(g_verbose, &nt); else (*np)[nt.id].print(g_verbose, &nt); } else { string_ex str; str.format("\rSuccess %d Failure %d ", g_overall_okay, g_overall_failure); if (g_map_path_nt.empty()) str += "Wait for Known USB Device Appear..."; if (!g_usb_path_filter.empty()) { str += " at path "; for (size_t i = 0; i < g_usb_path_filter.size(); i++) str += g_usb_path_filter[i] + " "; } print_oneline(str); print_oneline(""); if ((*np)[nt.id].m_dev == "Prep" && !g_start_usb_transfer) { Summary(np).print(); }else print_oneline(""); for (it = g_map_path_nt.begin(); it != g_map_path_nt.end(); it++) it->second.print(); for (size_t i = 0; i < g_map_path_nt.size() + 3; i++) cout << "\x1B[1F"; } //(*np)[nt.id] = g_map_path_nt[(*np)[nt.id].m_dev]; } if (nt.type == uuu_notify::NOTIFY_THREAD_EXIT) { if(np->find(nt.id) != np->end()) np->erase(nt.id); } return 0; } #ifdef _MSC_VER #define DEFINE_CONSOLEV2_PROPERTIES #include #include #include bool enable_vt_mode() { // Set output mode to handle virtual terminal sequences HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); if (hOut == INVALID_HANDLE_VALUE) { clean_vt_color(); return false; } DWORD dwMode = 0; if (!GetConsoleMode(hOut, &dwMode)) { clean_vt_color(); return false; } dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; if (!SetConsoleMode(hOut, dwMode)) { clean_vt_color(); return false; } return true; } int get_console_width() { CONSOLE_SCREEN_BUFFER_INFO sbInfo; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbInfo); return sbInfo.dwSize.X; } #else #include bool enable_vt_mode() { return true; } int get_console_width() { struct winsize w; ioctl(0, TIOCGWINSZ, &w); return w.ws_col; } #endif void print_usb_filter() { if (!g_usb_path_filter.empty()) { cout << " at path "; for (size_t i = 0; i < g_usb_path_filter.size(); i++) cout << g_usb_path_filter[i] << " "; } } int runshell(int shell) { int uboot_cmd = 0; string prompt = "U>"; if (shell) { cout << "Please input command: " << endl; string cmd; ofstream log("uuu.inputlog", ofstream::binary); log << "uuu_version " << ((uuu_get_version() & 0xFF0000) >> 16) << "." << ((uuu_get_version() & 0xFF00) >> 8) << "." << ((uuu_get_version() & 0xFF)) << endl; while (1) { cout << prompt; getline(cin, cmd); if (cmd == "uboot") { uboot_cmd = 1; prompt = "=>"; cout << "Enter into u-boot cmd mode" << endl; cout << "Okay" << endl; } else if (cmd == "exit" && uboot_cmd == 1) { uboot_cmd = 0; prompt = "U>"; cout << "Exit u-boot cmd mode" << endl; cout << "Okay" << endl; }else if (cmd == "help" || cmd == "?") { print_help(); } else if (cmd == "q" || cmd == "quit") { return 0; } else { log << cmd << endl; log.flush(); if (uboot_cmd) cmd = "fb: ucmd " + cmd; int ret = uuu_run_cmd(cmd.c_str(), 0); if (ret) cout << uuu_get_last_err_string() << endl; else cout << "Okay" << endl; } } return 0; } return -1; } void print_udev() { uuu_for_each_cfg(print_udev_rule, NULL); fprintf(stderr, "\n1: put above udev run into /etc/udev/rules.d/70-uuu.rules\n"); fprintf(stderr, "\tsudo sh -c \"uuu -udev >> /etc/udev/rules.d/70-uuu.rules\"\n"); fprintf(stderr, "2: update udev rule\n"); fprintf(stderr, "\tsudo udevadm control --reload\n"); } int print_usb_device(const char *path, const char *chip, const char *pro, uint16_t vid, uint16_t pid, uint16_t bcd, void * /*p*/) { printf("\t%s\t %s\t %s\t 0x%04X\t0x%04X\t 0x%04X\n", path, chip, pro, vid, pid, bcd); return 0; } void print_lsusb() { cout << "Connected Known USB Devices\n"; printf("\tPath\t Chip\t Pro\t Vid\t Pid\t BcdVersion\n"); printf("\t==================================================\n"); uuu_for_each_devices(print_usb_device, NULL); } #ifdef WIN32 int ignore_serial_number(const char *pro, const char *chip, const char */*comp*/, uint16_t vid, uint16_t pid, uint16_t /*bcdlow*/, uint16_t /*bcdhigh*/, void */*p*/) { printf("\t %s\t %s\t 0x%04X\t0x%04X\n", chip, pro, vid, pid); char sub[128]; snprintf(sub, 128, "IgnoreHWSerNum%04x%04x", vid, pid); const BYTE value = 1; LSTATUS ret = RegSetKeyValueA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\UsbFlags", sub, REG_BINARY, &value, 1); if(ret == ERROR_SUCCESS) return 0; printf("Set key failure, try run as administrator permission\n"); return -1; } #endif int set_ignore_serial_number() { #ifndef WIN32 printf("Only windows system need set ignore serial number registry"); return -1; #else printf("Set window registry to ignore usb hardware serial number for known uuu device:\n"); return uuu_for_each_cfg(ignore_serial_number, NULL); #endif } int main(int argc, char **argv) { if (auto_complete(argc, argv) == 0) return 0; if (argc >= 2) { string s = argv[1]; if(s == "-udev") { print_udev(); return 0; } if (s == "-bshow") { if (2 == argc || g_BuildScripts.find(argv[2]) == g_BuildScripts.end()) { fprintf(stderr, "Error, must be have script name: "); g_BuildScripts.ShowCmds(stderr); fprintf(stderr,"\n"); return -1; } else { string str = g_BuildScripts[argv[2]].m_text; while (str.size() > 0 && (str[0] == '\n' || str[0] == ' ')) str = str.erase(0,1); printf("%s", str.c_str()); return 0; } } } AutoCursor a; print_version(); if (!enable_vt_mode()) { cout << "Your console don't support VT mode, fail back to verbose mode" << endl; g_verbose = 1; } if (argc == 1) { print_help(); return 0; } int deamon = 0; int shell = 0; string filename; string cmd; int ret; int dryrun = 0; string cmd_script; for (int i = 1; i < argc; i++) { string s = argv[i]; if (!s.empty() && s[0] == '-') { if (s == "-d") { deamon = 1; }else if (s == "-s") { shell = 1; g_verbose = 1; } else if (s == "-v") { g_verbose = 1; } else if (s == "-V") { g_verbose = 1; uuu_set_debug_level(2); }else if (s == "-dry") { dryrun = 1; g_verbose = 1; } else if (s == "-h") { print_help(false); return 0; } else if (s == "-H") { print_help(true); return 0; } else if (s == "-m") { i++; uuu_add_usbpath_filter(argv[i]); g_usb_path_filter.push_back(argv[i]); } else if (s == "-t") { i++; uuu_set_wait_timeout(atoll(argv[i])); } else if (s == "-T") { i++; uuu_set_wait_next_timeout(atoll(argv[i])); } else if (s == "-pp") { i++; uuu_set_poll_period(atoll(argv[i])); } else if (s == "-lsusb") { print_lsusb(); return 0; } else if (s == "-IgSerNum") { return set_ignore_serial_number(); } else if (s == "-e") { #ifndef WIN32 #define _putenv putenv #endif i++; if (_putenv(argv[i])) { printf("error, failed to set '%s', environment parameter must have the form key=value\n", argv[i]); return -1; } } else if (s == "-b" || s == "-brun") { if (i + 1 == argc) { printf("error, must be have script name: "); g_BuildScripts.ShowCmds(); printf("\n"); return -1; } vector args; for (int j = i + 2; j < argc; j++) { string s = argv[j]; if (s.find(' ') != string::npos) { s.insert(s.begin(), '"'); s.insert(s.end(), '"'); } args.push_back(s); } // if script name is not build-in, try to look for a file if (g_BuildScripts.find(argv[i + 1]) == g_BuildScripts.end()) { const string tmpCmdFileName{argv[i + 1]}; std::ifstream t(tmpCmdFileName); std::string fileContents((std::istreambuf_iterator(t)), std::istreambuf_iterator()); if (fileContents.empty()) { printf("%s is not built-in script or fail load external script file", tmpCmdFileName.c_str()); return -1; } BuiltInScriptRawData tmpCmd{ tmpCmdFileName.c_str(), fileContents.c_str(), "Script loaded from file" }; g_BuildScripts.emplace(tmpCmdFileName, &tmpCmd); cmd_script = g_BuildScripts[tmpCmdFileName].replace_script_args(args); } else { cmd_script = g_BuildScripts[argv[i + 1]].replace_script_args(args); } break; } else { cout << "Unknown option: " << s.c_str(); return -1; } }else if (!s.empty() && s[s.size() - 1] == ':') { for (int j = i; j < argc; j++) { s = argv[j]; if (s.find(' ') != string::npos && s[s.size() - 1] != ':') { s.insert(s.begin(), '"'); s.insert(s.end(), '"'); } cmd.append(s); if(j != (argc -1)) /* Don't add space at last arg */ cmd.append(" "); } break; } else { filename = s; break; } } signal(SIGINT, ctrl_c_handle); if (deamon && shell) { printf("Error: -d -s Can't apply at the same time\n"); return -1; } if (deamon && dryrun) { printf("Error: -d -dry Can't apply at the same time\n"); return -1; } if (shell && dryrun) { printf("Error: -dry -s Can't apply at the same time\n"); return -1; } if (g_verbose) { printf("%sBuild in config:%s\n", g_vt_boldwhite, g_vt_default); printf("\tPctl\t Chip\t\t Vid\t Pid\t BcdVersion\n"); printf("\t==================================================\n"); uuu_for_each_cfg(print_cfg, NULL); if (!cmd_script.empty()) printf("\n%sRun built-in script:%s\n %s\n\n", g_vt_boldwhite, g_vt_default, cmd_script.c_str()); if (!shell) cout << "Wait for Known USB Device Appear..."; print_usb_filter(); printf("\n"); } else { cout << "Wait for Known USB Device Appear..."; print_usb_filter(); cout << "\r"; cout << "\x1b[?25l"; cout.flush(); } map nt_session; uuu_register_notify_callback(progress, &nt_session); if (!cmd.empty()) { ret = uuu_run_cmd(cmd.c_str(), dryrun); for (size_t i = 0; i < g_map_path_nt.size()+3; i++) printf("\n"); if(ret) printf("\nError: %s\n", uuu_get_last_err_string()); else printf("Okay\n"); runshell(shell); return ret; } if (!cmd_script.empty()) ret = uuu_run_cmd_script(cmd_script.c_str(), dryrun); else ret = uuu_auto_detect_file(filename.c_str()); if (ret) { ret = runshell(shell); if(ret) cout << g_vt_red << "\nError: " << g_vt_default << uuu_get_last_err_string(); return ret; } if (uuu_wait_uuu_finish(deamon, dryrun)) { cout << g_vt_red << "\nError: " << g_vt_default << uuu_get_last_err_string(); return -1; } runshell(shell); /*Wait for the other thread exit, after send out CMD_DONE*/ std::this_thread::sleep_for(std::chrono::milliseconds(100)); if(!g_verbose) printf("\n\n\n"); return g_overall_status; } mfgtools-uuu_1.4.193/uuu/uuu.lst000066400000000000000000000071701417203213400166030ustar00rootroot00000000000000uuu_version 1.0.0 # # uuu(universal update utility) command list file # Firstly line must be uuu_version show minimize uuu host version number # --------------------------------------------------------------------- # Command Format PROTOCOL COMMAND ARG # PROTOCOL # ALL protocol supported common command # done #last command for whole flow # delay # delay ms # sh\shell #Run shell command, such as wget to file from network # < #use shell command's output as uuu command # this command generally used for burn some sequence number, such production id, mac address # for example: # FB:< echo ucmd print # # CFG: Config protocol of specific usb device vid/pid # SDPS|SDP|FB\Fastboot|FBK -chip -pid -vid [-bcdversion ] # # SDPS: Stream download after MX8QXPB0 # boot -f [-offset 0x0000] # # SDP: iMX6/iMX7 HID download protocol. # dcd -f # write -f [-addr 0x000000] [-ivt 0] # jump -f [-ivt 0] # boot -f [-nojump] # rdmem -addr -format <8|16|32> # wrmem -addr -format <8|16|32> -value # # FB[-t timeout]:\Fastboot: android fastboot protocol. unit of timeout is ms # getvar # ucmd # acmd # flash [-raw2sparse] # download -f # # FBK: community with kernel with fastboot protocol. DO NOT compatible with fastboot tools. # ucmd and wait for command finish # acmd don't wait for command finish # sync wait for acmd process finish. # ucp copy file from/to target # T: means target board file. # T:- means copy data to target's stdio pipe. # copy image T:/root/image ;download image to path /root/image # copy T:/root/image image ;upload /root/image to file image. # Example for transfer big file # acmd tar - ; run tar background and get data from stdio # ucp rootfs.tar.gz T:- ; send to target stdio pipe # sync ; wait for tar process exit. # # For example: # SDPS: boot -f # SDP: boot -f # CFG: SDP: -chip imx6ull -pid 0x1234 -vid 0x5678 # # SDP: boot -f u-boot-imx7dsabresd_sd.imx -nojump # SDP: write -f zImage -addr 0x80800000 # SDP: write -f zImage-imx7d-sdb.dtb -addr 0x83000000 # SDP: write -f fsl-image-mfgtool-initramfs-imx_mfgtools.cpio.gz.u-boot -addr 0x83800000 # SDP: jump -f u-boot-dtb.imx -ivt CFG: FB: -vid 0x18D1 -pid 0x0D02 SDP: boot -f u-boot-dtb.imx FB: getvar version FB: ucmd setenv fastboot_buffer 0x80800000 FB: download -f zImage FB: ucmd setenv fastboot_buffer 0x83000000 FB: download -f zImage-imx7d-sdb.dtb FB: ucmd bootz 0x80800000 - 0x83000000 mfgtools-uuu_1.4.193/zlib/000077500000000000000000000000001417203213400153565ustar00rootroot00000000000000