├── CMakeLists.txt ├── LICENSE ├── README.md ├── bsdiff ├── bspatch.c ├── bspatch.h ├── vFile.c └── vFile.h ├── conanfile.py ├── lib ├── crc32.c ├── crc32.h ├── mylib.c └── mylib.h ├── lzma ├── 7zFile.c ├── 7zFile.h ├── 7zTypes.h ├── Compiler.h ├── LzFind.c ├── LzFind.h ├── LzHash.h ├── LzmaDec.c ├── LzmaDec.h ├── LzmaEnc.c ├── LzmaEnc.h ├── Precomp.h ├── lzma_decompress.c └── lzma_decompress.h └── user ├── bs_type.h ├── bs_user_interface.c └── bs_user_interface.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | ############################################################ 4 | # 用户设置部分 5 | ############################################################ 6 | set(PROJECT_USER_NAME bsdiff_upgrade) 7 | set(USER_LANGUAGES C)#设置代码中的所有语言类型,如C CXX ASM 8 | # set(PACKAGE_LIST cmsis-dsp)#本包依赖的包 9 | ############################################################ 10 | # Create a library 11 | ############################################################ 12 | # 查找当前目录下的所有源文件并将名称保存到 DIR_LIB_SRCS 变量 13 | file(GLOB_RECURSE DIR_LIB_SRCS 14 | "${CMAKE_CURRENT_LIST_DIR}/*.c" 15 | ) 16 | #搜索后排除不编译的特定文件 17 | # list(REMOVE_ITEM DIR_LIB_SRCS 18 | # "${CMAKE_CURRENT_LIST_DIR}/Source/TransformFunctions/TransformFunctionsF16.c" 19 | # ) 20 | 21 | #设置交叉编译环境,必备,否则会出现丢失libxxx的情况 22 | set(CMAKE_SYSTEM_NAME Generic) 23 | set(CMAKE_SYSTEM_PROCESSOR arm) 24 | set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) 25 | 26 | # linux 27 | if(CMAKE_HOST_UNIX) 28 | set(CMAKE_C_COMPILER_WORKS ON) 29 | set(CMAKE_CXX_COMPILER_WORKS ON) 30 | set(CMAKE_ASM_COMPILER_WORKS ON) 31 | endif() 32 | 33 | project(${PROJECT_USER_NAME} LANGUAGES ${USER_LANGUAGES}) 34 | 35 | #取DIR_LIB_SRCS中的第一个文件获取文件夹 36 | list(GET DIR_LIB_SRCS 0 FIRST_SRC) 37 | get_filename_component(DIR_LIB_SRCS_DIR ${FIRST_SRC} DIRECTORY) 38 | #获取conan路径 39 | string(REGEX MATCH "([^/]+/[^/]+/[^/]+/[^/]+)" DIR_LIB_SRCS_DIR_CONAN ${DIR_LIB_SRCS_DIR}) 40 | 41 | #设置在python基础上增加的编译选项,重点是优化等级 42 | if ("${CMAKE_C_COMPILER_ID}" STREQUAL "IAR")# using IAR 43 | string(APPEND C_FLAGS " -Oh") 44 | string(APPEND CXX_FLAGS " -Oh") 45 | elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "ARMCC")# using ARMCC 46 | string(APPEND C_FLAGS " -O3") 47 | string(APPEND CXX_FLAGS " -O3") 48 | elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")# using GNU 49 | string(APPEND C_FLAGS " -O2 -ffile-prefix-map=${DIR_LIB_SRCS_DIR_CONAN}=.") 50 | string(APPEND CXX_FLAGS " -O2 -ffile-prefix-map=${DIR_LIB_SRCS_DIR_CONAN}=.") 51 | endif() 52 | 53 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") 54 | message(Build type is Debug.) 55 | elseif(CMAKE_BUILD_TYPE STREQUAL "Release") 56 | string(APPEND C_FLAGS " -DNDEBUG") 57 | message(Build type is Release.) 58 | endif() 59 | 60 | message(${CMAKE_C_COMPILER_ID}) 61 | 62 | #优化等级 63 | set(CMAKE_C_FLAGS_DEBUG "" CACHE STRING INTERNAL FORCE) 64 | set(CMAKE_C_FLAGS_RELEASE "" CACHE STRING INTERNAL FORCE) 65 | 66 | # 当用了std LIB库的时候,需要处理包含编译器头文件路径 67 | if ("${CMAKE_C_COMPILER_ID}" STREQUAL "IAR")# using IAR 68 | #Set DLib_Config 69 | get_filename_component(COMPILER_DIR ${CMAKE_C_COMPILER} DIRECTORY) 70 | get_filename_component(COMPILER_DIR ${COMPILER_DIR} DIRECTORY) 71 | set(DLIB_CONFIG ${COMPILER_DIR}/inc/c/DLib_Config_Full.h) 72 | 73 | #linux下编译需要将路径转换为windows路径 74 | if(CMAKE_HOST_UNIX) 75 | execute_process ( 76 | COMMAND wslpath -w ${DLIB_CONFIG} 77 | OUTPUT_VARIABLE DLIB_CONFIG 78 | ) 79 | string(REPLACE "\n" "" DLIB_CONFIG ${DLIB_CONFIG}) #必须去掉换行符 80 | endif() 81 | #最终结果 82 | message(${DLIB_CONFIG}) 83 | string(APPEND C_FLAGS " --dlib_config \"${DLIB_CONFIG}\"") 84 | string(APPEND CXX_FLAGS " --dlib_config \"${DLIB_CONFIG}\"") 85 | endif() 86 | 87 | SET(CMAKE_C_FLAGS ${C_FLAGS}) 88 | SET(CMAKE_CXX_FLAGS ${CXX_FLAGS}) 89 | SET(CMAKE_ASM_FLAGS ${ASM_FLAGS}) 90 | 91 | #Generate the static library from the library sources 92 | add_library(${PROJECT_NAME} STATIC ${DIR_LIB_SRCS}) 93 | 94 | FOREACH(PACKAGE_LIST ${PACKAGE_LIST}) 95 | message("Current search ${PACKAGE_LIST} package...") #循环取值 96 | find_package(${PACKAGE_LIST} CONFIG REQUIRED) 97 | # Global approach 98 | if(${PACKAGE_LIST}_FOUND) 99 | message(${${PACKAGE_LIST}_INCLUDE_DIRS}) 100 | target_include_directories(${PROJECT_NAME} PRIVATE ${${PACKAGE_LIST}_INCLUDE_DIRS}) 101 | target_link_libraries(${PROJECT_NAME} 102 | PRIVATE 103 | ${${PACKAGE_LIST}_LIB_DIRS_RELEASE}/lib${PACKAGE_LIST}.a 104 | ) 105 | endif() 106 | ENDFOREACH(PACKAGE_LIST) 107 | 108 | #head file 109 | file(GLOB_RECURSE Head_Files 110 | "${CMAKE_CURRENT_SOURCE_DIR}/*.h" 111 | ) 112 | #查找头文件路径 113 | FOREACH(Head_Files ${Head_Files}) 114 | string(REGEX REPLACE "(.*/)" "" HEAD_FILE ${Head_Files})#匹配文件名 115 | string(REPLACE ${HEAD_FILE} "" HEAD_FILE_DIR ${Head_Files})#去除文件名 116 | list(APPEND HEAD_INCLUDE_DIR ${HEAD_FILE_DIR})#添加到列表 117 | ENDFOREACH(Head_Files) 118 | #路径去重 119 | list(REMOVE_DUPLICATES HEAD_INCLUDE_DIR) 120 | #指定编译时包含的头文件路径 121 | target_include_directories(${PROJECT_NAME} 122 | PUBLIC 123 | ${HEAD_INCLUDE_DIR} 124 | ) 125 | message(${CMAKE_CURRENT_SOURCE_DIR}) 126 | #安装所有头文件 127 | install(FILES ${Head_Files} DESTINATION include) 128 | install(TARGETS ${PROJECT_NAME}) 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 适用于嵌入式单片机的差分升级库,通用所有单片机,如stm32、华大、复旦微、瑞萨等。适合嵌入式的差分升级又叫增量升级,顾名思义就是通过差分算法将源版本与目标版本之间差异的部分提取出来制作成差分包,然后在设备通过还原算法将差异部分在源版本上进行还原从而升级成目标版本的过程。 差分升级方案不仅可以节省MCU内部的资源空间、还可以节省下载流程及下载和升级过程中的功耗。技术支持vx 18219255930,qq791314247 4 | 5 | 我将更详细的教程内容放在了我的博客: 6 | 7 | [代码说明:https://blog.csdn.net/qq_35333978/article/details/128211763?spm=1001.2014.3001.5501](https://blog.csdn.net/qq_35333978/article/details/128211763?spm=1001.2014.3001.5501) 8 | 9 | PS:很多人调不通99%都是因为申请内存那里有问题,要么malloc是自己写的、移植的有问题,要么就是给的堆内存不够。该套源码很多人用了很多工程都没问题的,基本无bug,如果调不通,注意以下几点: 10 | 11 | 1. 可以先用malloc测试,堆内存给20k以上,如果想缩减也是可以,需要修改源码每次还原的长度小一点,目前每次还原1k。 12 | 2. 检查堆、栈,如果调不通,可以先给比较大的值测试,基本不是堆就是栈的问题,源码是没有问题的,大量人测试过的。 13 | 14 | # 修改日志 15 | 16 | V1.0.1: 17 | 18 | 1,增加CMakeList.txt和conanfile.py文件,可以直接生成conan库,用不上conan库的不用关心这两个文件,删除即可 19 | 20 | 2,修改动态内存申请接口,从宏定义的方式升级为注册接口,宏的方式用户始终得修改代码,新版注册的方式,整个代码用户完全不用修改,注册的例子如下: 21 | 22 | ``` 23 | /** 24 | * @brief Initializes the upgrade module. 25 | * 26 | * This function sets up the necessary function pointers and registers them with the 27 | * bs_user_func_register() function. It assigns the xmq25qxx_write() function to the 28 | * bs_flash_write function pointer, and assigns the pvPortMalloc() and vPortFree() 29 | * functions to the bs_malloc and bs_free function pointers respectively. 30 | */ 31 | void UpgradeInit(void) 32 | { 33 | bs_user_interface bsFunc; 34 | 35 | bsFunc.bs_flash_write = xmq25qxxWrite; 36 | bsFunc.bs_malloc = (bs_malloc_func)pvPortMalloc; 37 | bsFunc.bs_free = vPortFree; 38 | bs_user_func_register(&bsFunc); 39 | } 40 | ``` 41 | 42 | 3,该版本整体修改没有动任何逻辑,只是优化了接口 43 | 44 | 45 | # 详细介绍 46 | 47 | # 1. 什么是差分/增量升级? 48 | 49 | 借用网上的介绍:适合嵌入式的差分升级又叫增量升级,顾名思义就是通过差分算法将源版本与目标版本之间差异的部分提取出来制作成差分包,然后在设备通过还原算法将差异部分在源版本上进行还原从而升级成目标版本的过程。 差分升级方案不仅可以节省MCU内部的资源空间、还可以节省下载流程及下载和升级过程中的功耗。 50 | 51 | 也就是说,差分升级是拿以前旧设备内的bin,和当前新版本的bin用某种算法算出他们的差异部分,然后在借助压缩算法,生产一个极其小的差分包,然后将这个差分包下载到设备中,设备在根据解压算法、差分还原算法,生产一个完整的新版本bin,然后将这个新版本bin刷到执行区执行代码。 52 | 53 | 差分升级一般来说,可以极大的减少下载量,特别是对于嵌入式STM32等单片机来说,可以极大的减少维护成本,因为嵌入式设备的升级维护一般都是空中ota升级,比如蓝牙、红外等,下载速度受到波特率、包长等限制,更新固件包非常的慢,而差分升级可以让下载的过程极大的缩小。正常的维护版本,即使改的再多,生成的差分包bin理论上在原bin的5%左右,比如一个300k的bin,改的很多的情况下差分包也不过15k左右,而我实际测试,版本维护平均都在5~10k左右。 54 | 55 | # 2. 差分升级实现原理 56 | 57 | 差分升级过程: 58 | 59 | 1. 使用旧版本bin文件和新版本bin文件制作差分包 60 | 2. 将差分包下载到设备内 61 | 3. 设备使用差分算法还原出新版本bin 62 | 4. 设备将新版本bin进行crc验证后刷到代码执行区 63 | 5. 设备重启并以新版本运行 64 | 65 | 在过程中有2个关键点: 66 | 67 | **第一:如何使用旧版本bin****文件和新版本bin****文件制作差分包?** 68 | 69 | 该过程我们使用稳定的开源差分算法bsdiff+lzma生成差分包,该算法被大量使用,稳定安全,并且我们已在项目中批量使用,经过长时间的验证无任何问题。一般来说,该过程都是使用上位机来完成,嵌入式设备无需关心,我们已经做好了上位机软件,可以供大家随意使用,稍后会进行介绍。 70 | 71 | **第二:设备收到差分包后如何还原出新版本的bin****文件?** 72 | 73 | 该过程就是我们要讲解的重点过程,相对应的,嵌入式设备中,我们依然使用开源差分算法bsdiff+lzma来还原新版本文件,代码全开源,并且我已做成了库、抽象出了极简的接口,移植起来费不了多少功夫,基本是市场上所有的单片机如stm32、瑞萨、华大、复旦微等都可以使用,但是有内存限制,要求ram至少要10k以上,然后是该库本身的消耗大概是5k的rom。 74 | 75 | # 3. 关键点一:差分包制作过程 76 | 77 | 对于差分包的制作,我已经开发好了上位机软件,界面如下图所示: 78 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/8a4a092094774282ab6239c33fd6eebd.png) 79 | 上位机这边主要实现使用开源算法bsdiff制作旧版本bin和新版本bin的差分包,然后在使用lzma压缩算法来压缩差分包,最终生成一个差分bin,使用方法上位机界面提示的很清楚,最终效果如下图所示: 80 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/bd6cc76b8f2945278fd74f2b1dd075d5.png) 81 | 下载链接: 82 | 83 | 链接:[https://pan.baidu.com/s/1nBpftim8OCUI3i32sP3eOA?pwd=diff ](https://pan.baidu.com/s/1nBpftim8OCUI3i32sP3eOA?pwd=diff) 84 | 85 | 提取码:diff 86 | 87 | # 4. 关键点二:嵌入式设备中差分算法库的移植(还原差分包) 88 | 89 | ## 4.1. 移植开关算法库代码 90 | 91 | 整体代码如下图所示: 92 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/c13c11642a1c4e04ba756b4960cc4800.png) 93 | 如上图所示,99%的代码用户都不用去关心,用户只需要提供一个flash写入接口即可,也就是该库给定用户flash地址、数据内容指针、数据内容长度,用户将该段数据写入到flash即可,移植起来特别简单,花不了几分钟的功夫,这也是我花大力气抽象接口的原因。 94 | 95 | ## 4.2. 使用该库的流程 96 | 97 | ### 4.2.1. 使用库的接口 98 | 99 | 对于整个库的代码,我们只需要关心一个接口iap_patch,iap_patch在文件”bs_user_func.h”中。 100 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/f9748aa6f4684926a05ff4aa7bbd2a1d.png) 101 | 102 | 该接口介绍也比较清晰,差分包的还原,只需要调用这一个接口即可。 103 | 104 | ```c 105 | /** 106 | * @brief 用户使用差分升级时唯一需要关心的接口 107 | * 108 | * @param old 设备中执行区代码所在的地址,用户可指定flash执行区的地址,方便算法读出来当前 109 | * 运行中的代码 110 | * @param oldsize 设备中执行区代码的长度,用户可在差分包bin头获取 111 | * @param patch 设备中已经下载的差分包所在的flash地址,或者ram地址,只要能让算法读出来即可 112 | * 注意,下载的差分包自带image_header_t格式的文件头,真正的差分包需要偏 113 | * 移sizeof(image_header_t)的长度 114 | * @param patchsize 设备中已经下载的差分包的长度,用户可在差分包bin头获取 115 | * @param newfile 新文件的大小,用户需填入新版本bin的长度,用户亦可以差分包bin头获取 116 | * @return int 然后错误码,0成功,1失败 117 | */ 118 | extern int iap_patch(const uint8_t* old, uint32_t oldsize, const uint8_t* patch, 119 | uint32_t patchsize, uint32_t newfile); 120 | ``` 121 | 122 | 另外,使用该接口还原时所需要的一些信息可以在差分包文件头中获取,上位机在制作差分包时,会自动在差分包的bin头加上64字节的文件头,以便于告诉嵌入式设备旧/新版本bin文件的CRC校验、长度等信息。所以用户在收到差分包头时,偏移掉这64个字节的文件头的地址才是需要给到iap_patch接口的真正的bin文件。文件头格式如下代码,用户只需要关心中文注释的部分,其余的都是预留的信息。 123 | 124 | ```c 125 | /* 差分包制作时自带的文件头信息,用户只需要关心中文注释的部分 */ 126 | typedef struct image_header 127 | { 128 | uint32_t ih_magic; /* Image Header Magic Number */ 129 | uint32_t ih_hcrc; /* Image Header CRC Checksum 差分包包头校验 */ 130 | uint32_t ih_time; /* Image Creation Timestamp */ 131 | uint32_t ih_size; /* Image Data Size 差分包的大小 */ 132 | uint32_t ih_load; /* Data Load Address 上一版本旧文件的大小 */ 133 | uint32_t ih_ep; /* Entry Point Address 要升级的新文件的大小 */ 134 | uint32_t ih_dcrc; /* Image Data CRC Checksum 新文件的CRC */ 135 | uint8_t ih_os; /* Operating System */ 136 | uint8_t ih_arch; /* CPU architecture */ 137 | uint8_t ih_type; /* Image Type */ 138 | uint8_t ih_comp; /* Compression Type */ 139 | uint8_t ih_name[IH_NMLEN]; /* Image Name */ 140 | uint32_t ih_ocrc; /* Old Image Data CRC Checksum 上一版本旧文件的CRC */ 141 | } image_header_t; 142 | /* 差分包制作时自带的文件头信息,用户只需要关心中文注释的部分 */ 143 | ``` 144 | 145 | ### 4.2.2. 接口使用例子 146 | 147 | 我截取一段我工程中的代码来讲解如何使用该接口还原出新版本bin文件: 148 | 149 | ```c 150 | 1#ifdef BSDIFF_UPGRADE 151 | 2 image_header_t recv_head; 152 | 3 uint32_t recv_hcrc; /* 接收到的文件头CRC */ 153 | 4 uint32_t calculation_crc; /* 计算出来的文件头CRC */ 154 | 5 uint32_t spi_flash_addr = UPGRADE_PROGRAM_ADDR; 155 | 6 156 | 7 memcpy(&recv_head, (uint8_t *)APPLICATION_A, sizeof(image_header_t)); 157 | 8 recv_hcrc = BigtoLittle32(recv_head.ih_hcrc); 158 | 9 recv_head.ih_hcrc = 0; 159 | 10 calculation_crc = crc32((uint8_t *)&recv_head, sizeof(image_header_t)); 160 | 11 161 | 12 if (recv_hcrc == calculation_crc) 162 | 13 { 163 | 14 recv_head.ih_hcrc = recv_hcrc; 164 | 15 recv_head.ih_time = BigtoLittle32(recv_head.ih_time); 165 | 16 recv_head.ih_size = BigtoLittle32(recv_head.ih_size); 166 | 17 recv_head.ih_dcrc = BigtoLittle32(recv_head.ih_dcrc); 167 | 18 recv_head.ih_ocrc = BigtoLittle32(recv_head.ih_ocrc); 168 | 19 /* 差分升级包 */ 169 | 20 recv_head.ih_hcrc = calculation_crc; 170 | 21 if (crc32((uint8_t *)APPLICATION_RUN, recv_head.ih_load) != recv_head.ih_ocrc) 171 | 22 { 172 | 23 APP_ERR_PRINT("file oldcrc err,calcrc:0X%08X, ih_oldbin_crc:0X%08X,", 173 | 24 crc32((uint8_t *)APPLICATION_RUN, 174 | 25 recv_head.ih_load), recv_head.ih_ocrc); 175 | 26 goto bsdiff_out; 176 | 27 } 177 | 28 RTOS_LOCK(); 178 | 29 disable_task_monitoring(ALL_TASK_RUNFLAG_BIT, true); 179 | 30 // flash_erase_sector(UPGRADE_PROGRAM_ADDR, UPGRADE_PROGRAM_PAGE); 180 | 31 recv_hcrc = iap_patch((uint8_t *)APPLICATION_RUN, recv_head.ih_load, 181 | 32 (uint8_t *)(APPLICATION_A + sizeof(image_header_t)), 182 | 33 recv_head.ih_size, UPGRADE_PROGRAM_ADDR); 183 | 34 if (recv_hcrc != recv_head.ih_ep) 184 | 35 { 185 | 36 APP_ERR_PRINT("iap_patch len err."); 186 | 37 APP_ERR_PRINT("iap_patch len: %lu, new_len: %lu", recv_hcrc, recv_head.ih_ep); 187 | 38 goto bsdiff_out; 188 | 39 } 189 | 40 if (erase_program(APPLICATION_A)) 190 | 41 { 191 | 42 APP_ERR_PRINT("I erase program failed."); 192 | 43 goto bsdiff_out; 193 | 44 } 194 | 45 195 | 46 current_flash_write_addr = APPLICATION_A; 196 | 47 for (uint32_t i = 0; i < (recv_head.ih_ep / 1024); i++) 197 | 48 { 198 | 49 xmq25qxx_read(spi_flash_addr, spi_read_cache, 1024); 199 | 50 if (xflash_write(current_flash_write_addr, spi_read_cache, 1024)) 200 | 51 { 201 | 52 APP_ERR_PRINT("I write program failed."); 202 | 53 goto bsdiff_out; 203 | 54 } 204 | 55 spi_flash_addr += 1024; 205 | 56 current_flash_write_addr += 1024; 206 | 57 APP_PRINT("current_flash_write_addr: 0X%08X", current_flash_write_addr); 207 | 58 } 208 | 59 if (recv_head.ih_ep % 1024 != 0) 209 | 60 { 210 | 61 memset(spi_read_cache, 0XFF, 1024); 211 | 62 xmq25qxx_read(spi_flash_addr, spi_read_cache, recv_head.ih_ep % 1024); 212 | 63 213 | 64 if (xflash_write(current_flash_write_addr, spi_read_cache, 1024)) 214 | 65 { 215 | 66 APP_ERR_PRINT("I write program failed."); 216 | 67 goto bsdiff_out; 217 | 68 } 218 | 69 } 219 | 70 if (crc32((uint8_t *)APPLICATION_A, recv_head.ih_ep) != recv_head.ih_dcrc) 220 | 71 { 221 | 72 APP_ERR_PRINT("file newcrc err,calcrc:0X%08X, newcrc:0X%08X, len: %lu", 222 | 73 crc32((uint8_t *)APPLICATION_A, recv_head.ih_ep), 223 | 74 recv_head.ih_load, recv_head.ih_dcrc); 224 | 75 goto bsdiff_out; 225 | 76 } 226 | 77 /* 下载成功,开始升级 */ 227 | 78 if (check_bin_file((bin_info_t *)(APPLICATION_A + BIN_INFO_OFFSET))) /* bin文件非法 */ 228 | 79 { 229 | 80 APP_ERR_PRINT("check_bin_file err."); 230 | 81 goto bsdiff_out; 231 | 82 } 232 | 83 recv_head.ih_dcrc = CRT_CRC16_check(0, (uint8_t *)APPLICATION_A, 233 | 84 recv_head.ih_ep); 234 | 85 readwrite_app_run_bin_info(0, &recv_head.ih_ep, (uint16_t *)&recv_head.ih_dcrc); 235 | 86 /* 整体校验成功,确认升级 */ 236 | 87 if (switch_program_stage(STAGE_1)) 237 | 88 { 238 | 89 APP_ERR_PRINT("I write switch_program_stage STAGE_0 failed."); /* 置位升级标志写失败 */ 239 | 90 goto bsdiff_out; 240 | 91 } 241 | 92 APP_PRINT("upgrade success."); 242 | 93 bsdiff_out: 243 | 94 SYSTEM_RESET(); 244 | 95 } 245 | 246 | ``` 247 | -------------------------------------------------------------------------------- /bsdiff/bspatch.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * Copyright 2012 Matthew Endsley 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include "bspatch.h" 32 | #include "vFile.h" 33 | #include "bs_user_interface.h" 34 | 35 | #define WRITE_BLOCK_SIZE 1024 36 | 37 | int64_t offtin(uint8_t *buf) 38 | { 39 | int64_t y; 40 | 41 | y = buf[7] & 0x7F; 42 | y = y * 256; 43 | y += buf[6]; 44 | y = y * 256; 45 | y += buf[5]; 46 | y = y * 256; 47 | y += buf[4]; 48 | y = y * 256; 49 | y += buf[3]; 50 | y = y * 256; 51 | y += buf[2]; 52 | y = y * 256; 53 | y += buf[1]; 54 | y = y * 256; 55 | y += buf[0]; 56 | 57 | if (buf[7] & 0x80) 58 | { 59 | y = -y; 60 | } 61 | 62 | return y; 63 | } 64 | 65 | int bspatch(const uint8_t *old, int64_t oldsize, int64_t newsize, struct bspatch_stream *stream) 66 | { 67 | uint8_t buf[8]; 68 | uint8_t *buf_data; 69 | int64_t oldpos, newpos, len; 70 | int64_t ctrl[3]; 71 | int64_t i; 72 | 73 | buf_data = (uint8_t *)vmalloc(WRITE_BLOCK_SIZE + 1); 74 | 75 | if (buf_data == NULL) 76 | { 77 | return -1; 78 | } 79 | 80 | oldpos = 0; 81 | newpos = 0; 82 | 83 | while (newpos < newsize) 84 | { 85 | /* Read control data */ 86 | for (i = 0; i <= 2; i++) 87 | { 88 | if (stream->read(stream, buf, 8)) 89 | { 90 | bs_printf("err%d", __LINE__); 91 | return -1; 92 | } 93 | 94 | ctrl[i] = offtin(buf); 95 | }; 96 | 97 | /* Sanity-check */ 98 | if (ctrl[0] < 0 || ctrl[0] > INT_MAX || 99 | ctrl[1] < 0 || ctrl[1] > INT_MAX || 100 | newpos + ctrl[0] > newsize) 101 | { 102 | bs_printf("err%d", __LINE__); 103 | return -1; 104 | } 105 | 106 | /* Read diff string */ 107 | while (ctrl[0] > 0) 108 | { 109 | if (ctrl[0] > WRITE_BLOCK_SIZE) 110 | { 111 | len = WRITE_BLOCK_SIZE; 112 | } 113 | else 114 | { 115 | len = ctrl[0]; 116 | } 117 | 118 | if (stream->read(stream, buf_data, len)) 119 | { 120 | return -1; 121 | } 122 | 123 | for (i = 0; i < len; i++) 124 | { 125 | if ((oldpos + i >= 0) && (oldpos + i < oldsize)) 126 | { 127 | buf_data[i] += old[oldpos + i]; 128 | } 129 | } 130 | 131 | stream->write(stream, buf_data, len); 132 | ctrl[0] -= len; 133 | oldpos += len; 134 | newpos += len; 135 | } 136 | 137 | /* Sanity-check */ 138 | if (newpos + ctrl[1] > newsize) 139 | { 140 | bs_printf("err%d", __LINE__); 141 | return -1; 142 | } 143 | 144 | /* Read extra string */ 145 | while (ctrl[1] > 0) 146 | { 147 | if (ctrl[1] > WRITE_BLOCK_SIZE) 148 | { 149 | len = WRITE_BLOCK_SIZE; 150 | } 151 | else 152 | { 153 | len = ctrl[1]; 154 | } 155 | 156 | if (stream->read(stream, buf_data, len)) 157 | { 158 | return -1; 159 | } 160 | 161 | stream->write(stream, buf_data, len); 162 | ctrl[1] -= len; 163 | newpos += len; 164 | } 165 | 166 | /* Adjust pointers */ 167 | oldpos += ctrl[2]; 168 | //printk("newpos = %d, ctrl[0] = %ld, ctrl[1] = %ld, ctrl[2] = %ld\n", newpos, ctrl[0], ctrl[1], ctrl[2]); 169 | }; 170 | 171 | if (buf_data != NULL) 172 | { 173 | vfree(buf_data); 174 | } 175 | 176 | return 0; 177 | } 178 | 179 | //=========================================================== 180 | #include "lzma_decompress.h" 181 | #include "vFile.h" 182 | #include "bs_user_interface.h" 183 | 184 | #ifndef TRUE 185 | #define TRUE 1 186 | #endif 187 | 188 | #ifndef FALSE 189 | #define FALSE 0 190 | #endif 191 | 192 | #define DCOMPRESS_BUFFER_SIZE 1024 193 | static uint8_t *diff_data_buff; 194 | static int diff_data_len, diff_data_fp; 195 | static int new_data_fp; 196 | 197 | static int patch_data_read(const struct bspatch_stream *stream, void *buffer, int length) 198 | { 199 | uint8_t *dp = (uint8_t *)buffer; 200 | vFile *pf; 201 | 202 | pf = (vFile *) stream->opaque_r; 203 | 204 | for (int i = 0; i < length; i++) 205 | { 206 | if (diff_data_len == 0) 207 | { 208 | diff_data_len = lzma_decompress_read(pf, diff_data_buff, DCOMPRESS_BUFFER_SIZE); 209 | 210 | if (diff_data_len > 0) 211 | { 212 | diff_data_fp = 0; 213 | } 214 | else 215 | { 216 | bs_printf("err%d", __LINE__); 217 | return -1; 218 | } 219 | } 220 | 221 | if (diff_data_len > 0) 222 | { 223 | *(dp++) = diff_data_buff[diff_data_fp++]; 224 | diff_data_len--; 225 | } 226 | } 227 | 228 | return 0; 229 | } 230 | 231 | static int new_data_write(const struct bspatch_stream *stream, void *buffer, int length) 232 | { 233 | uint32_t file_addr; 234 | 235 | if (bs_user_func.bs_flash_write == NULL) 236 | { 237 | bs_printf("err"); 238 | return (FALSE); 239 | } 240 | 241 | file_addr = *((uint32_t *)stream->opaque_w); 242 | 243 | if (0 != bs_user_func.bs_flash_write(file_addr + new_data_fp, buffer, length)) 244 | { 245 | bs_printf("err"); 246 | } 247 | 248 | new_data_fp += length; 249 | 250 | return (TRUE); 251 | } 252 | 253 | static void patch_data_read_finish(void) 254 | { 255 | lzma_decompress_finish(); 256 | 257 | } 258 | 259 | /** 260 | * @brief 解压并还原文件,用户使用差分升级时唯一需要关心的接口 261 | * 262 | * @param old 设备中执行区代码所在的地址,用户可指定flash执行区的地址,方便算法读出来当前 263 | * 运行中的代码,用户提供 264 | * @param oldsize 设备中执行区代码的长度,用户可在差分包bin头获取,用户提供 265 | * @param patch 设备中已经下载的差分包所在的flash地址,或者ram地址,只要能让算法读出来即可 266 | * 注意,下载的差分包自带image_header_t格式的文件头,真正的差分包需要偏 267 | * 移sizeof(image_header_t)的长度,用户提供 268 | * @param patchsize 设备中已经下载的差分包的长度,用户提供,可在差分包bin头获取 269 | * @param newfile 还原后的bin写入的地址,用户提供 270 | * @return int 还原的文件大小 271 | */ 272 | int iap_patch(const uint8_t *old, uint32_t oldsize, const uint8_t *patch, uint32_t patchsize, uint32_t newfile_addr) 273 | { 274 | vFile *patch_fp; 275 | struct bspatch_stream stream; 276 | uint8_t header[24]; 277 | int64_t newsize; 278 | 279 | //初始化全局变量 280 | diff_data_len = 0; 281 | diff_data_fp = 0; 282 | new_data_fp = 0; 283 | patch_fp = vfopen(patch, patchsize); 284 | 285 | if (patch_fp == NULL) 286 | { 287 | bs_printf("Line 224 vmalloc err"); 288 | return (0); 289 | } 290 | 291 | //读取差分文件头 292 | vfread(patch_fp, header, sizeof(header)); 293 | bs_printf("patch_fp->offset:%d", patch_fp->offset); 294 | 295 | if (memcmp(header, "ENDSLEY/BSDIFF43", 16) != 0) 296 | { 297 | bs_printf("ENDSLEY/BSDIFF43 err: %s", header); 298 | 299 | for (uint32_t i = 0; i < sizeof(header); i++) 300 | { 301 | bs_printf("%02X ", header[i]); 302 | } 303 | 304 | return (0); 305 | } 306 | 307 | //计算新固件长度 308 | newsize = offtin(header + 16); 309 | 310 | if (newsize < 0) 311 | { 312 | bs_printf("newsize err"); 313 | return (0); 314 | } 315 | 316 | //分配内存 317 | diff_data_buff = vmalloc(DCOMPRESS_BUFFER_SIZE); 318 | 319 | if (diff_data_buff == NULL) 320 | { 321 | bs_printf("\r\nmalloc err"); 322 | return (0); 323 | } 324 | 325 | //准备合并文件 326 | stream.read = patch_data_read; 327 | stream.opaque_r = (void *)patch_fp; 328 | stream.write = new_data_write; 329 | stream.opaque_w = &newfile_addr; 330 | 331 | int res = bspatch(old, oldsize, newsize, &stream); 332 | (void)res; 333 | bs_printf("bspatch res:%d", res); 334 | 335 | //释放内存 336 | patch_data_read_finish(); 337 | vfree(diff_data_buff); 338 | vfclose(patch_fp); 339 | 340 | return ((int)newsize); 341 | } 342 | -------------------------------------------------------------------------------- /bsdiff/bspatch.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * Copyright 2012 Matthew Endsley 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef BSPATCH_H 29 | # define BSPATCH_H 30 | 31 | # include 32 | 33 | struct bspatch_stream 34 | { 35 | void* opaque_r; 36 | int (*read)(const struct bspatch_stream* stream, void* buffer, int length); 37 | 38 | void* opaque_w; 39 | int (*write)(const struct bspatch_stream* stream, void* buffer, int length); 40 | }; 41 | 42 | int64_t offtin(uint8_t *buf); 43 | int bspatch(const uint8_t* old, int64_t oldsize, int64_t newsize, struct bspatch_stream* stream); 44 | 45 | #endif 46 | 47 | -------------------------------------------------------------------------------- /bsdiff/vFile.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file vFile.c 4 | * @author eming 5 | * @version V1.0.0 6 | * @date 2022-03-21 7 | * @brief 虚拟文件接口,将保存在内部Flash的数据虚拟为文件 8 | ****************************************************************************** 9 | */ 10 | 11 | #include 12 | #include 13 | #include "vFile.h" 14 | #include "bs_user_interface.h" 15 | 16 | 17 | void *vmalloc(size_t size) 18 | { 19 | if (bs_user_func.bs_malloc == NULL) 20 | { 21 | return NULL; 22 | } 23 | return bs_user_func.bs_malloc((size_t)size); 24 | } 25 | 26 | void vfree(void *ptr) 27 | { 28 | if (bs_user_func.bs_free == NULL) 29 | { 30 | return; 31 | } 32 | bs_user_func.bs_free(ptr); 33 | } 34 | 35 | vFile *vfopen(const uint8_t *dp, uint32_t size) 36 | { 37 | vFile *fp = NULL; 38 | 39 | fp = vmalloc(sizeof(vFile)); 40 | if (fp != NULL) 41 | { 42 | fp->curptr = (uint8_t *)dp; 43 | fp->offset = 0; 44 | fp->size = size; 45 | } 46 | 47 | return (fp); 48 | } 49 | 50 | int vfread(vFile *fp, uint8_t *buff, int len) 51 | { 52 | if (fp != NULL) 53 | { 54 | if ((fp->offset + len) > fp->size) 55 | { 56 | len = fp->size - fp->offset; 57 | } 58 | memcpy(buff, fp->curptr + fp->offset, len); 59 | fp->offset += len; 60 | 61 | return (len); 62 | } 63 | 64 | return (0); 65 | } 66 | 67 | uint8_t *vfgetpos(vFile *fp, uint32_t *position) 68 | { 69 | if (fp != NULL) 70 | { 71 | *position = fp->offset; 72 | 73 | return (fp->curptr + fp->offset); 74 | } 75 | 76 | return (NULL); 77 | } 78 | 79 | int vfsetpos(vFile *fp, uint32_t position) 80 | { 81 | if (fp != NULL) 82 | { 83 | fp->offset = position; 84 | return (fp->offset); 85 | } 86 | return -1; 87 | } 88 | 89 | int vfclose(vFile *fp) 90 | { 91 | if (fp != NULL) 92 | { 93 | vfree(fp); 94 | } 95 | 96 | return (0); 97 | } 98 | 99 | uint32_t vfgetlen(vFile *fp) 100 | { 101 | return (fp->size); 102 | } 103 | 104 | /******************************************************************************************************* 105 | ** End Of File 106 | ********************************************************************************************************/ 107 | 108 | -------------------------------------------------------------------------------- /bsdiff/vFile.h: -------------------------------------------------------------------------------- 1 | #ifndef __VFILE_H__ 2 | #define __VFILE_H__ 3 | /*******************************************************************************************************/ 4 | #include "stdint.h" 5 | 6 | typedef struct 7 | { 8 | uint8_t *curptr; 9 | uint32_t offset; 10 | uint32_t size; 11 | }vFile; 12 | 13 | /*******************************************************************************************************/ 14 | vFile *vfopen(const uint8_t *dp, uint32_t size); 15 | int vfread(vFile *fp, uint8_t *buff, int len); 16 | uint8_t *vfgetpos(vFile *fp, uint32_t *position); 17 | int vfsetpos(vFile *fp, uint32_t position); 18 | int vfclose(vFile *fp); 19 | uint32_t vfgetlen(vFile *fp); 20 | void *vmalloc(size_t size); 21 | void vfree(void *ptr); 22 | 23 | #endif 24 | /******************************************************************************************************* 25 | ** End Of File 26 | ********************************************************************************************************/ 27 | -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | from conan import ConanFile 2 | from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps 3 | 4 | 5 | class helloRecipe(ConanFile): 6 | name = "bsdiff_upgrade" 7 | version = "1.0.3" 8 | user = "xian" 9 | channel = "stable" #"stable" or "testing" 10 | 11 | # Sources are located in the same place as this recipe, copy them to the recipe 12 | exports_sources = "CMakeLists.txt", "readme.md", "bsdiff/*", "lib/*", "lzma/*", "user/*" 13 | 14 | #依赖包 15 | #requires = "cmsis-dsp/5.8.0@xian/stable" 16 | 17 | # Optional metadata 18 | license = "zc" 19 | author = "wangrui" 20 | url = "" 21 | description = "static libraries" 22 | 23 | # Binary configuration 24 | settings = "os", "compiler", "build_type", "arch" 25 | options = {"shared": [True, False], "fPIC": [True, False]} 26 | default_options = {"shared": False, "fPIC": False} 27 | 28 | def config_options(self): 29 | if self.settings.os == "Windows": 30 | self.options.rm_safe("fPIC") 31 | 32 | def configure(self): 33 | if self.options.shared: 34 | self.options.rm_safe("fPIC") 35 | #del self.settings.compiler.cppstd 36 | #del self.settings.compiler.libcxx 37 | 38 | def layout(self): 39 | cmake_layout(self) 40 | 41 | def generate(self): 42 | deps = CMakeDeps(self) 43 | deps.generate() 44 | tc = CMakeToolchain(self) 45 | if self.settings.compiler == "keil": 46 | if self.settings.arch == "Cortex-M4F": 47 | tc.variables["C_FLAGS"] = "--cpu Cortex-M4.fp.sp -O3 --c99 -c -D__MICROLIB --apcs=interwork --split_sections --diag_suppress=186,66" 48 | tc.variables["CXX_FLAGS"] = "--cpu Cortex-M4.fp.sp -O3 --c99 -c -D__MICROLIB --apcs=interwork --split_sections --diag_suppress=186,66" 49 | tc.variables["ASM_FLAGS"] = "--cpu Cortex-M4.fp.sp -g --apcs=interwork --pd '__MICROLIB SETA 1'" 50 | elif self.settings.arch == "Cortex-M4": 51 | tc.variables["C_FLAGS"] = "--cpu Cortex-M4 -O3 --c99 -c -D__MICROLIB --apcs=interwork --split_sections --diag_suppress=186,66" 52 | tc.variables["CXX_FLAGS"] = "--cpu Cortex-M4 -O3 --c99 -c -D__MICROLIB --apcs=interwork --split_sections --diag_suppress=186,66" 53 | tc.variables["ASM_FLAGS"] = "--cpu Cortex-M4 -g --apcs=interwork --pd '__MICROLIB SETA 1'" 54 | elif self.settings.arch == "Cortex-M3": 55 | tc.variables["C_FLAGS"] = "--cpu Cortex-M3 -O3 --c99 -c -D__MICROLIB --apcs=interwork --split_sections --diag_suppress=186,66" 56 | tc.variables["CXX_FLAGS"] = "--cpu Cortex-M3 -O3 --c99 -c -D__MICROLIB --apcs=interwork --split_sections --diag_suppress=186,66" 57 | tc.variables["ASM_FLAGS"] = "--cpu Cortex-M3 -g --apcs=interwork --pd '__MICROLIB SETA 1'" 58 | elif self.settings.arch == "Cortex-M0": 59 | tc.variables["C_FLAGS"] = "--cpu Cortex-M0 -O3 --c99 -c -D__MICROLIB --apcs=interwork --split_sections --diag_suppress=186,66" 60 | tc.variables["CXX_FLAGS"] = "--cpu Cortex-M0 -O3 --c99 -c -D__MICROLIB --apcs=interwork --split_sections --diag_suppress=186,66" 61 | tc.variables["ASM_FLAGS"] = "--cpu Cortex-M0 -g --apcs=interwork --pd '__MICROLIB SETA 1'" 62 | elif self.settings.compiler == "iar": 63 | if self.settings.arch == "Cortex-M4F": 64 | tc.variables["C_FLAGS"] = "--silent --no_code_motion --endian=little --cpu=Cortex-M4 --fpu=VFPv4_sp" 65 | tc.variables["CXX_FLAGS"] = "--silent --no_code_motion --endian=little --cpu=Cortex-M4 --fpu=VFPv4_sp" 66 | tc.variables["ASM_FLAGS"] = "--silent --no_code_motion --endian=little --cpu=Cortex-M4 --fpu=VFPv4_sp" 67 | elif self.settings.arch == "Cortex-M4": 68 | tc.variables["C_FLAGS"] = "--silent --no_code_motion --endian=little --cpu=Cortex-M4" 69 | tc.variables["CXX_FLAGS"] = "--silent --no_code_motion --endian=little --cpu=Cortex-M4" 70 | tc.variables["ASM_FLAGS"] = "--silent --no_code_motion --endian=little --cpu=Cortex-M4" 71 | elif self.settings.arch == "Cortex-M0": 72 | tc.variables["C_FLAGS"] = "--silent --no_code_motion --endian=little --cpu=Cortex-M0" 73 | tc.variables["CXX_FLAGS"] = "--silent --no_code_motion --endian=little --cpu=Cortex-M0" 74 | tc.variables["ASM_FLAGS"] = "--silent --no_code_motion --endian=little --cpu=Cortex-M0" 75 | elif self.settings.compiler == "arm-gcc": 76 | if self.settings.arch == "Cortex-M4F": #带fpu 77 | tc.variables["C_FLAGS"] = "-x c -mcpu=cortex-m4 -mthumb -Wstack-protector -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu99 -fdata-sections -ffunction-sections --param max-inline-insns-single=500 -Wall -Wunused -Wuninitialized -Wformat -Wformat-security -Wunknown-pragmas -Wundef -Wbad-function-cast -Wwrite-strings -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wunreachable-code -Werror" 78 | tc.variables["CXX_FLAGS"] = "-x c -mcpu=cortex-m4 -mthumb -Wstack-protector -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu99 -fdata-sections -ffunction-sections --param max-inline-insns-single=500 -Wall -Wunused -Wuninitialized -Wformat -Wformat-security -Wunknown-pragmas -Wundef -Wbad-function-cast -Wwrite-strings -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wunreachable-code -Werror" 79 | tc.variables["ASM_FLAGS"] = "-x assembler -c -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu99 --param max-inline-insns-single=500 -Wall -Wunused -Wuninitialized -Wformat -Wformat-security -Wunknown-pragmas -Wundef -Wbad-function-cast -Wwrite-strings -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wunreachable-code" 80 | elif self.settings.arch == "Cortex-M4": #不带fpu 81 | tc.variables["C_FLAGS"] = "-x c -mcpu=cortex-m4 -mthumb -Wstack-protector -std=gnu99 -fdata-sections -ffunction-sections --param max-inline-insns-single=500 -Wall -Wunused -Wuninitialized -Wformat -Wformat-security -Wunknown-pragmas -Wundef -Wbad-function-cast -Wwrite-strings -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wunreachable-code -Werror" 82 | tc.variables["CXX_FLAGS"] = "-x c -mcpu=cortex-m4 -mthumb -Wstack-protector -std=gnu99 -fdata-sections -ffunction-sections --param max-inline-insns-single=500 -Wall -Wunused -Wuninitialized -Wformat -Wformat-security -Wunknown-pragmas -Wundef -Wbad-function-cast -Wwrite-strings -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wunreachable-code -Werror" 83 | tc.variables["ASM_FLAGS"] = "-x assembler -c -mcpu=cortex-m4 -mthumb -std=gnu99 --param max-inline-insns-single=500 -Wall -Wunused -Wuninitialized -Wformat -Wformat-security -Wunknown-pragmas -Wundef -Wbad-function-cast -Wwrite-strings -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wunreachable-code" 84 | elif self.settings.arch == "Cortex-M0": #不带fpu 85 | tc.variables["C_FLAGS"] = "-x c -mcpu=cortex-m0 -mthumb -Wstack-protector -std=gnu99 -fdata-sections -ffunction-sections --param max-inline-insns-single=500 -Wall -Wunused -Wuninitialized -Wformat -Wformat-security -Wunknown-pragmas -Wundef -Wbad-function-cast -Wwrite-strings -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wunreachable-code -Werror" 86 | tc.variables["CXX_FLAGS"] = "-x c -mcpu=cortex-m0 -mthumb -Wstack-protector -std=gnu99 -fdata-sections -ffunction-sections --param max-inline-insns-single=500 -Wall -Wunused -Wuninitialized -Wformat -Wformat-security -Wunknown-pragmas -Wundef -Wbad-function-cast -Wwrite-strings -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wunreachable-code -Werror" 87 | tc.variables["ASM_FLAGS"] = "-x assembler -c -mcpu=cortex-m0 -mthumb -std=gnu99 --param max-inline-insns-single=500 -Wall -Wunused -Wuninitialized -Wformat -Wformat-security -Wunknown-pragmas -Wundef -Wbad-function-cast -Wwrite-strings -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wunreachable-code" 88 | else: 89 | print(f"arch发生错误: no arch.") 90 | sys.exit(1) # 退出并返回一个非零状态码 91 | elif self.settings.compiler == "gcc": 92 | tc.variables["C_FLAGS"] = "-x c -fdata-sections -ffunction-sections -Wall -std=gnu99" 93 | tc.variables["CXX_FLAGS"] = "-x c -fdata-sections -ffunction-sections -Wall -std=gnu99" 94 | tc.variables["ASM_FLAGS"] = "" 95 | tc.variables["CMAKE_C_COMPILER_WORKS"] = 1 96 | tc.variables["CMAKE_CXX_COMPILER_WORKS"] = 1 97 | tc.variables["WITH_WINDOWS_GCC"] = True 98 | else: 99 | print(f"compiler发生错误: no compiler.") 100 | sys.exit(1) # 退出并返回一个非零状态码 101 | tc.generate() 102 | 103 | def build(self): 104 | cmake = CMake(self) 105 | cmake.configure() 106 | cmake.build() 107 | 108 | def package(self): 109 | cmake = CMake(self) 110 | cmake.install() 111 | 112 | def package_info(self): 113 | self.cpp_info.libs = [self.name] 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /lib/crc32.c: -------------------------------------------------------------------------------- 1 | /** 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | 7 | #include 8 | 9 | const unsigned int crc32tab[] = 10 | { 11 | 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 12 | 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 13 | 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 14 | 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 15 | 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 16 | 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 17 | 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 18 | 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 19 | 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 20 | 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 21 | 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 22 | 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 23 | 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 24 | 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 25 | 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 26 | 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 27 | 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 28 | 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 29 | 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 30 | 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 31 | 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 32 | 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 33 | 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 34 | 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 35 | 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 36 | 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 37 | 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 38 | 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 39 | 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 40 | 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 41 | 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 42 | 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 43 | 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 44 | 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 45 | 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 46 | 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 47 | 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 48 | 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 49 | 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 50 | 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 51 | 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 52 | 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 53 | 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 54 | 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 55 | 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 56 | 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 57 | 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 58 | 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 59 | 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 60 | 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 61 | 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 62 | 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 63 | 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 64 | 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 65 | 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 66 | 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 67 | 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 68 | 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 69 | 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 70 | 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 71 | 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 72 | 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 73 | 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 74 | 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL 75 | }; 76 | 77 | 78 | unsigned int crc32( const unsigned char *buf, unsigned int size) 79 | { 80 | unsigned int i, crc; 81 | crc = 0xFFFFFFFF; 82 | 83 | for (i = 0; i < size; i++) 84 | { 85 | crc = crc32tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8); 86 | } 87 | return crc ^ 0xFFFFFFFF; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /lib/crc32.h: -------------------------------------------------------------------------------- 1 | #ifndef __CRC32_H__ 2 | #define __CRC32_H__ 3 | /*******************************************************************************************************/ 4 | extern unsigned int crc32( const unsigned char *buf, unsigned int size); 5 | 6 | #endif 7 | /******************************************************************************************************* 8 | ** End Of File 9 | ********************************************************************************************************/ 10 | -------------------------------------------------------------------------------- /lib/mylib.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file mylib.c 4 | * @author eming 5 | * @version V1.0.0 6 | * @date 2022-03-21 7 | * @brief 定义一些公用函数 8 | ****************************************************************************** 9 | */ 10 | #include "stdint.h" 11 | // #include "ustdio.h" 12 | #include "stdlib.h" 13 | #include "string.h" 14 | #include "time.h" 15 | #include "bs_type.h" 16 | 17 | /** 18 | * @brief 和校验 19 | * @details 字节数组的和校验函数 20 | * 21 | * @param *p 数组指针 22 | * @param size 数组长度 23 | * @return 求和结果 24 | * @retval 无 25 | */ 26 | uint32_t mylib_sum(const uint8_t *p, uint16_t size) 27 | { 28 | uint32_t sum = 0; 29 | 30 | while(size--) 31 | { 32 | sum += *(p++); 33 | } 34 | return(sum); 35 | } 36 | 37 | /** 38 | * @brief 数据比较 39 | * @details 字节数组的数据比较 40 | * 41 | * @param *p1 数组1指针 42 | * @param *p2 数组2指针 43 | * @param size 比较的数据块大小 44 | * @return 比较结果 45 | * @retval TRUE 相等 46 | * @retval FALSE 不相等 47 | */ 48 | int mylib_memcmp(const void *p1, const void *p2, int size) 49 | { 50 | uint8_t *bp1, *bp2; 51 | 52 | bp1 = (uint8_t*)p1; 53 | bp2 = (uint8_t*)p2; 54 | while(size--) 55 | { 56 | if(*(bp1++) != *(bp2++))return(FALSE); 57 | } 58 | return(TRUE); 59 | } 60 | 61 | /** 62 | * @brief 数据比较 63 | * @details 字节数组与指定数据比较 64 | * 65 | * @param *p1 数组指针 66 | * @param value 被比较的数值 67 | * @param size 比较的数据块大小 68 | * @return 比较结果 69 | * @retval TRUE 相等 70 | * @retval FALSE 不相等 71 | */ 72 | int mylib_memcmp_b(uint8_t *p1, uint8_t value, int size) 73 | { 74 | while(size--) 75 | { 76 | if(*(p1++) != value)return(FALSE); 77 | } 78 | return(TRUE); 79 | } 80 | 81 | /** 82 | * @brief 延时函数 83 | * @details 大概为1uS的延时函数 84 | * 85 | * @param us 需要延时的微秒数 86 | * @return 无 87 | * @retval 无 88 | */ 89 | void mylib_uDelay(uint32_t us) 90 | { 91 | int i; 92 | 93 | for(; us > 0; us--) 94 | { 95 | for(i = 0; i < 40; i++); 96 | } 97 | } 98 | 99 | /** 100 | * @brief CRC16函数 101 | * @details 计算字节数组的CRC16 102 | * 103 | * @param *p 数组指针 104 | * @param size 数组长度 105 | * @return 计算结果 106 | * @retval uint16_t CRC16值 107 | */ 108 | uint16_t mylib_crc16(uint8_t *p, uint16_t size) 109 | { 110 | uint16_t crc; //校验码 111 | uint16_t i; 112 | uint16_t j; 113 | crc = 0xFFFF; 114 | for (i = 0; i < size; i++) 115 | { 116 | crc ^= *p; 117 | for (j = 0; j < 8; j++) 118 | { 119 | if ((crc & 1) == 1) 120 | { 121 | crc >>= 1; 122 | crc ^= 0xA001; 123 | } 124 | else 125 | { 126 | crc >>= 1; 127 | } 128 | } 129 | p++; 130 | } 131 | return(crc); 132 | } 133 | 134 | /** 135 | * @brief 16位大小端转换 136 | * @details 数据大端小段互相转换函数 137 | * 138 | * @param *frm 源数组指针 139 | * @param *to 目标数组指针 140 | * @param size 转换的数据个数(半字) 141 | * @return 无 142 | * @retval 无 143 | */ 144 | void mylib_BigtoLittle16(const void *frm, void *to, uint16_t size) 145 | { 146 | uint8_t buff[2]; 147 | uint8_t *fp, *tp; 148 | 149 | fp = (uint8_t *)frm; 150 | tp = (uint8_t *)to; 151 | while(size--) 152 | { 153 | buff[0] = fp[0]; 154 | buff[1] = fp[1]; 155 | tp[0] = buff[1]; 156 | tp[1] = buff[0]; 157 | 158 | tp += 2; 159 | fp += 2; 160 | } 161 | } 162 | 163 | /** 164 | * @brief 32位大小端转换 165 | * @details 数据大端小段互相转换函数 166 | * 167 | * @param *frm 源数组指针 168 | * @param *to 目标数组指针 169 | * @param size 转换的数据个数(字) 170 | * @return 无 171 | * @retval 无 172 | */ 173 | void mylib_BigtoLittle32(const void *frm, void *to, uint16_t size) 174 | { 175 | uint8_t buff[4]; 176 | uint8_t *fp, *tp; 177 | 178 | fp = (uint8_t *)frm; 179 | tp = (uint8_t *)to; 180 | while(size--) 181 | { 182 | buff[0] = fp[0]; 183 | buff[1] = fp[1]; 184 | buff[2] = fp[2]; 185 | buff[3] = fp[3]; 186 | tp[0] = buff[3]; 187 | tp[1] = buff[2]; 188 | tp[2] = buff[1]; 189 | tp[3] = buff[0]; 190 | 191 | tp += 4; 192 | fp += 4; 193 | } 194 | } 195 | 196 | /** 197 | * @brief 64位浮点数大小端转换 198 | * @details 数据大端小段互相转换函数 199 | * 200 | * @param dat 浮点数 201 | * @return 转换结果 202 | * @retval 转换后的浮点数 203 | */ 204 | double mylib_BigtoLittle_fp64(double dat) 205 | { 206 | F64_U8 tmp1, tmp2; 207 | 208 | tmp1.f64 = dat; 209 | tmp2.d8[0] = tmp1.d8[7]; 210 | tmp2.d8[1] = tmp1.d8[6]; 211 | tmp2.d8[2] = tmp1.d8[5]; 212 | tmp2.d8[3] = tmp1.d8[4]; 213 | tmp2.d8[4] = tmp1.d8[3]; 214 | tmp2.d8[5] = tmp1.d8[2]; 215 | tmp2.d8[6] = tmp1.d8[1]; 216 | tmp2.d8[7] = tmp1.d8[0]; 217 | 218 | return(tmp2.f64); 219 | } 220 | 221 | /** 222 | * @brief BCD编码函数 223 | * @details 二进制数据转BCD码 224 | * 225 | * @param hex 二进制数据 226 | * @return 转换结果 227 | * @retval BCD码 228 | */ 229 | uint8_t mylib_HEXtoBCD(uint8_t hex) 230 | { 231 | uint8_t bcd = 0; 232 | 233 | bcd = hex / 10; 234 | bcd <<= 4; 235 | bcd += hex % 10; 236 | 237 | return(bcd); 238 | } 239 | 240 | /** 241 | * @brief BCD解码函数 242 | * @details BCD码转二进制数据 243 | * 244 | * @param bcd BCD码数据 245 | * @return 转换结果 246 | * @retval 二进制数据 247 | */ 248 | uint8_t mylib_BCDtoHEX(uint8_t bcd) 249 | { 250 | uint8_t hex = 0; 251 | 252 | hex = ((bcd >> 4) & 0x0F) * 10 + (bcd & 0x0F); 253 | return(hex); 254 | } 255 | 256 | /** 257 | * @brief 数值转字符串 258 | * @details 整形数值转字符串 259 | * 260 | * @param value 整形数值 261 | * @param *str 转换结果字符串指针 262 | * @param radix 进制 263 | * @return 换结果字符串指针 264 | */ 265 | char *my_itoa(int value, char *str, uint8_t radix) 266 | { 267 | static char szMap[] = 268 | { 269 | '0', '1', '2', '3', '4', '5', 270 | '6', '7', '8', '9', 'a', 'b', 271 | 'c', 'd', 'e', 'f', 'g', 'h', 272 | 'i', 'j', 'k', 'l', 'm', 'n', 273 | 'o', 'p', 'q', 'r', 's', 't', 274 | 'u', 'v', 'w', 'x', 'y', 'z' 275 | }; // 字符映射表 276 | int nCount = -1, nIndex; 277 | char *pStr = str, nTemp; 278 | unsigned int nValue = *(unsigned *)&value; 279 | 280 | if(radix >= 2 && radix <= 36 ) //限制radix必须在2到36之间 281 | { 282 | if(value < 0 && radix == 10) //如果是负数就在首位添加负号,并将字符串前移 283 | { 284 | *pStr++ = '-'; 285 | value = -value; //转为正数, 286 | } 287 | do //循环转换每一个数字,直到结束 288 | { 289 | pStr[++nCount] = szMap[nValue % radix]; 290 | nValue /= radix; 291 | } 292 | while(nValue > 0); //转换结束后字符串是翻的 293 | nIndex = (nCount + 1) / 2; //计算出一半的长度 294 | while(nIndex-- > 0) //将字符串的字符序翻转 295 | { 296 | nTemp = pStr[nIndex]; 297 | pStr[nIndex] = pStr[nCount - nIndex]; 298 | pStr[nCount - nIndex] = nTemp; 299 | } 300 | } 301 | pStr[nCount + 1] = '\0'; // 置结束符 302 | return str; 303 | } 304 | 305 | /** 306 | * @brief 数组转字符串 307 | * @details 字节数组转字符串 308 | * 309 | * @param *str 转换后的字符串 310 | * @param bytes 被转换的字节数组 311 | * @param size 被转换的字节数组长度 312 | * @return 转换出的字符串长度 313 | */ 314 | int mylib_bytes_to_string(char *str, const uint8_t *bytes, int size) 315 | { 316 | int i; 317 | 318 | char hexArray[] = "0123456789ABCDEF"; 319 | 320 | for (i = 0; i < size; i++) 321 | { 322 | int v = bytes[i] & 0xFF; 323 | str[i * 2] = hexArray[v >> 4]; 324 | str[i * 2 + 1] = hexArray[v & 0x0F]; 325 | } 326 | str[size * 2] = '\0'; 327 | 328 | return (size * 2); 329 | } 330 | 331 | /** 332 | * @brief 字符串转数组 333 | * @details 字符串转字节数组 334 | * 335 | * @param *str 被转换的字符串 336 | * @param bytes 转换出的字节数组 337 | * @return 转换出的字节数组长度 338 | */ 339 | int mylib_string_to_bytes(char *str, uint8_t *bytes) 340 | { 341 | uint8_t tmp, tmp1; 342 | uint16_t len; 343 | uint16_t dat_len; 344 | 345 | len = strlen(str); 346 | if(len % 2) //检查是否为偶数 347 | { 348 | str[len] = '0'; //补0 349 | len++; 350 | str[len] = '\0'; 351 | } 352 | dat_len = len / 2; 353 | while(len) 354 | { 355 | if((*str > 47) && (*str < 58)) //0~9 356 | { 357 | tmp = *str - 48; 358 | } 359 | else if((*str > 64) && (*str < 71)) //A~F 360 | { 361 | tmp = *str - 55; 362 | } 363 | else if((*str > 96) && (*str < 103)) //a~f 364 | { 365 | tmp = *str - 87; 366 | } 367 | else 368 | { 369 | tmp = 32; 370 | } 371 | tmp <<= 4; 372 | str++; 373 | if((*str > 47) && (*str < 58)) //0~9 374 | { 375 | tmp1 = *str - 48; 376 | } 377 | else if((*str > 64) && (*str < 71)) //A~F 378 | { 379 | tmp1 = *str - 55; 380 | } 381 | else if((*str > 96) && (*str < 103)) //a~f 382 | { 383 | tmp1 = *str - 87; 384 | } 385 | else 386 | { 387 | tmp1 = 32; 388 | } 389 | tmp += tmp1; 390 | *(bytes++) = tmp; 391 | str++; 392 | len -= 2; 393 | } 394 | 395 | return(dat_len); 396 | } 397 | 398 | /** 399 | * @brief 大小写转换 400 | * @details 将字符串中的大写字符变为小写字符 401 | * 402 | * @param *str 被转换的字符串 403 | * @return 转换出的字符串 404 | */ 405 | char *strlwr(char *str) 406 | { 407 | uint16_t len; 408 | char *p; 409 | 410 | len = strlen(str); 411 | p = str; 412 | while(len--) 413 | { 414 | if((*p > 64) && (*p < 91)) 415 | { 416 | *p += 32; 417 | } 418 | p++; 419 | } 420 | return(str); 421 | } 422 | 423 | /** 424 | * @brief 字符串提取数字 425 | * @details 字符串提取数字字符,去除其他符号 426 | * 427 | * @param *str 被处理的字符串 428 | * @param *num 结果字符串 429 | * @return 提取出的字符串长度 430 | */ 431 | int strval(char *str, char *num) 432 | { 433 | int len = 0; 434 | 435 | while(*str != '\0') 436 | { 437 | if((*str > 47) && (*str < 58)) 438 | { 439 | *num = *str; 440 | num++; 441 | len++; 442 | } 443 | str++; 444 | } 445 | *num = '\0'; 446 | 447 | return(len); 448 | } 449 | 450 | /** 451 | * @brief 打印16进制数据 452 | * @details 由于调试时输出二进制数据 453 | * 454 | * @param *p 二进制数据指针 455 | * @param size 数据长度 456 | * @return 无 457 | */ 458 | void printk_hex(const uint8_t *p, int size) 459 | { 460 | // int i; 461 | 462 | // for(i = 0; i < size; i++) 463 | // { 464 | // printk(" %02X", *(p++)); 465 | // } 466 | } 467 | 468 | /** 469 | * @brief utc秒转时间 470 | * @details 包含时区参数 471 | * 472 | * @param utc_s utc秒 473 | * @param *t 转换结果 474 | * @param tz 时区 475 | * @return 无 476 | */ 477 | void utc_to_time(uint32_t utc_s, struct tm *t, int tz) 478 | { 479 | #define SECOND_OF_DAY 86400 //1天的秒数 480 | uint16_t i, j, iDay; 481 | uint32_t lDay; 482 | const uint8_t DayOfMon[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 483 | 484 | utc_s += 3600 * tz; //时区 485 | 486 | lDay = utc_s / SECOND_OF_DAY; 487 | utc_s = utc_s % SECOND_OF_DAY; 488 | 489 | i = 1970; //星期取值为0-6 490 | t->tm_wday = (lDay + 3) % 7; //1970年1月1号是星期4 491 | while(lDay > 365) 492 | { 493 | if(((i % 4 == 0) && (i % 100 != 0)) || (i % 400 == 0)) // 闰年 494 | lDay -= 366; 495 | else 496 | lDay -= 365; 497 | i++; 498 | } 499 | if((lDay == 365) && !(((i % 4 == 0) && (i % 100 != 0)) || (i % 400 == 0))) //平年 500 | { 501 | lDay -= 365; 502 | i++; 503 | } 504 | t->tm_year = i - 1900; //得到年份 505 | for(j = 0; j < 12; j++) //计算月份 506 | { 507 | if((j == 1) && (((i % 4 == 0) && (i % 100 != 0)) || (i % 400 == 0))) 508 | iDay = 29; 509 | else 510 | iDay = DayOfMon[j]; 511 | if(lDay >= iDay) lDay -= iDay; 512 | else break; 513 | } 514 | t->tm_mon = j; 515 | t->tm_mday = lDay + 1; 516 | t->tm_hour = utc_s / 3600; 517 | t->tm_min = (utc_s % 3600) / 60; 518 | t->tm_sec = (utc_s % 3600) % 60; 519 | } 520 | 521 | /** 522 | * @brief 计算日期是一年中的那一天 523 | * @details 计算日期的年索引,2月当做29天算 524 | * 525 | * @param utc_s utc秒 526 | * @param *t 转换结果 527 | * @param tz 时区 528 | * @return 无 529 | */ 530 | int mylib_day_index(uint8_t mon, uint8_t day) 531 | { 532 | const uint8_t Line_Mon_Len[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 533 | int index = 0; 534 | int i; 535 | 536 | if((mon < 1) || (mon > 12))return(0); //参数判断 537 | if((day < 1) || (day > 31))return(0); 538 | 539 | for(i = 1; i < mon; i++) 540 | { 541 | index += Line_Mon_Len[i - 1]; 542 | } 543 | index += day - 1; 544 | 545 | return(index); 546 | } 547 | 548 | /** 549 | * @brief 16进制字符串转数据 550 | * @details 16进制字符串转数据,可以包含"0x"头 551 | * 552 | * @param *s 字符串 553 | * @return 提取的数值 554 | */ 555 | int tolower(int c) 556 | { 557 | if (c >= 'A' && c <= 'Z') 558 | { 559 | return c + 'a' - 'A'; 560 | } 561 | else 562 | { 563 | return c; 564 | } 565 | } 566 | 567 | uint32_t htoi(const char *s) 568 | { 569 | int i; 570 | uint32_t n = 0; 571 | 572 | if (s[0] == '0' && (s[1]=='x' || s[1]=='X')) 573 | { 574 | i = 2; 575 | } 576 | else 577 | { 578 | i = 0; 579 | } 580 | for (; (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z') || (s[i] >='A' && s[i] <= 'Z');++i) 581 | { 582 | if (tolower(s[i]) > '9') 583 | { 584 | n = 16 * n + (10 + tolower(s[i]) - 'a'); 585 | } 586 | else 587 | { 588 | n = 16 * n + (tolower(s[i]) - '0'); 589 | } 590 | } 591 | return n; 592 | } 593 | 594 | /** 595 | * @brief 返回堆内存的大小 596 | * @details 返回堆内存的大小 597 | * 598 | * @param *mp 堆内存指针 599 | * @return 堆内存的大小 600 | */ 601 | uint32_t _msize(const void *mp) 602 | { 603 | return(*((int*)((uint32_t)mp - 4))); 604 | } 605 | 606 | /******************************************************************************************************* 607 | ** End Of File 608 | ********************************************************************************************************/ 609 | 610 | 611 | -------------------------------------------------------------------------------- /lib/mylib.h: -------------------------------------------------------------------------------- 1 | #ifndef __MYLIB_H 2 | #define __MYLIB_H 3 | /*********************************************************************************************************/ 4 | #include "stdint.h" 5 | #include "time.h" 6 | #include "bs_type.h" 7 | 8 | 9 | uint32_t mylib_sum(const uint8_t *p, uint16_t size); 10 | int mylib_memcmp(const void *p1, const void *p2, int size); 11 | int mylib_memcmp_b(uint8_t *p1, uint8_t value, int size); 12 | void mylib_uDelay(uint32_t us); 13 | uint16_t mylib_crc16(uint8_t *p, uint16_t size); 14 | void mylib_BigtoLittle16(const void *frm, void *to, uint16_t size); 15 | void mylib_BigtoLittle32(const void *frm, void *to, uint16_t size); 16 | double mylib_BigtoLittle_fp64(double dat); 17 | uint8_t mylib_HEXtoBCD(uint8_t hex); 18 | uint8_t mylib_BCDtoHEX(uint8_t bcd); 19 | char *my_itoa(int value, char *str, uint8_t radix); 20 | int mylib_bytes_to_string(char *str, const uint8_t *bytes, int size); 21 | int mylib_string_to_bytes(char *str, uint8_t *bytes); 22 | char *strlwr(char *str); 23 | int strval(char *str, char *num); 24 | void printf_hex(const uint8_t *p, int size); 25 | void utc_to_time(uint32_t utc_s, struct tm *t, int tz); 26 | int mylib_day_index(uint8_t mon, uint8_t day); 27 | uint32_t htoi(const char *s); 28 | uint32_t _msize(const void *mp); 29 | 30 | 31 | /*********************************************************************************************************/ 32 | #endif 33 | /******************************************************************************************************* 34 | ** End Of File 35 | ********************************************************************************************************/ 36 | 37 | -------------------------------------------------------------------------------- /lzma/7zFile.c: -------------------------------------------------------------------------------- 1 | /* 7zFile.c -- File IO 2 | 2017-04-03 : Igor Pavlov : Public domain */ 3 | 4 | #include "Precomp.h" 5 | 6 | #include "7zFile.h" 7 | 8 | #ifndef USE_WINDOWS_FILE 9 | 10 | #ifndef UNDER_CE 11 | #include 12 | #endif 13 | 14 | #else 15 | 16 | /* 17 | ReadFile and WriteFile functions in Windows have BUG: 18 | If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) 19 | from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES 20 | (Insufficient system resources exist to complete the requested service). 21 | Probably in some version of Windows there are problems with other sizes: 22 | for 32 MB (maybe also for 16 MB). 23 | And message can be "Network connection was lost" 24 | */ 25 | 26 | #define kChunkSizeMax (1 << 22) 27 | 28 | #endif 29 | 30 | void File_Construct(CSzFile *p) 31 | { 32 | #ifdef USE_WINDOWS_FILE 33 | p->handle = INVALID_HANDLE_VALUE; 34 | #else 35 | p->file = NULL; 36 | #endif 37 | } 38 | 39 | #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) 40 | static WRes File_Open(CSzFile *p, const char *name, int writeMode) 41 | { 42 | #ifdef USE_WINDOWS_FILE 43 | p->handle = CreateFileA(name, 44 | writeMode ? GENERIC_WRITE : GENERIC_READ, 45 | FILE_SHARE_READ, NULL, 46 | writeMode ? CREATE_ALWAYS : OPEN_EXISTING, 47 | FILE_ATTRIBUTE_NORMAL, NULL); 48 | return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); 49 | #else 50 | p->file = fopen(name, writeMode ? "wb+" : "rb"); 51 | return (p->file != 0) ? 0 : 52 | #ifdef UNDER_CE 53 | 2; /* ENOENT */ 54 | #else 55 | errno; 56 | #endif 57 | #endif 58 | } 59 | 60 | WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } 61 | WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); } 62 | #endif 63 | 64 | #ifdef USE_WINDOWS_FILE 65 | static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) 66 | { 67 | p->handle = CreateFileW(name, 68 | writeMode ? GENERIC_WRITE : GENERIC_READ, 69 | FILE_SHARE_READ, NULL, 70 | writeMode ? CREATE_ALWAYS : OPEN_EXISTING, 71 | FILE_ATTRIBUTE_NORMAL, NULL); 72 | return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); 73 | } 74 | WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } 75 | WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } 76 | #endif 77 | 78 | WRes File_Close(CSzFile *p) 79 | { 80 | #ifdef USE_WINDOWS_FILE 81 | if (p->handle != INVALID_HANDLE_VALUE) 82 | { 83 | if (!CloseHandle(p->handle)) 84 | return GetLastError(); 85 | p->handle = INVALID_HANDLE_VALUE; 86 | } 87 | #else 88 | if (p->file != NULL) 89 | { 90 | int res = fclose(p->file); 91 | if (res != 0) 92 | return res; 93 | p->file = NULL; 94 | } 95 | #endif 96 | return 0; 97 | } 98 | 99 | WRes File_Read(CSzFile *p, void *data, size_t *size) 100 | { 101 | size_t originalSize = *size; 102 | if (originalSize == 0) 103 | return 0; 104 | 105 | #ifdef USE_WINDOWS_FILE 106 | 107 | *size = 0; 108 | do 109 | { 110 | DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; 111 | DWORD processed = 0; 112 | BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); 113 | data = (void *)((Byte *)data + processed); 114 | originalSize -= processed; 115 | *size += processed; 116 | if (!res) 117 | return GetLastError(); 118 | if (processed == 0) 119 | break; 120 | } 121 | while (originalSize > 0); 122 | return 0; 123 | 124 | #else 125 | 126 | *size = fread(data, 1, originalSize, p->file); 127 | if (*size == originalSize) 128 | return 0; 129 | return ferror(p->file); 130 | 131 | #endif 132 | } 133 | 134 | WRes File_Write(CSzFile *p, const void *data, size_t *size) 135 | { 136 | size_t originalSize = *size; 137 | if (originalSize == 0) 138 | return 0; 139 | 140 | #ifdef USE_WINDOWS_FILE 141 | 142 | *size = 0; 143 | do 144 | { 145 | DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; 146 | DWORD processed = 0; 147 | BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); 148 | data = (void *)((Byte *)data + processed); 149 | originalSize -= processed; 150 | *size += processed; 151 | if (!res) 152 | return GetLastError(); 153 | if (processed == 0) 154 | break; 155 | } 156 | while (originalSize > 0); 157 | return 0; 158 | 159 | #else 160 | 161 | *size = fwrite(data, 1, originalSize, p->file); 162 | if (*size == originalSize) 163 | return 0; 164 | return ferror(p->file); 165 | 166 | #endif 167 | } 168 | 169 | WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) 170 | { 171 | #ifdef USE_WINDOWS_FILE 172 | 173 | LARGE_INTEGER value; 174 | DWORD moveMethod; 175 | value.LowPart = (DWORD)*pos; 176 | value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ 177 | switch (origin) 178 | { 179 | case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; 180 | case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; 181 | case SZ_SEEK_END: moveMethod = FILE_END; break; 182 | default: return ERROR_INVALID_PARAMETER; 183 | } 184 | value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); 185 | if (value.LowPart == 0xFFFFFFFF) 186 | { 187 | WRes res = GetLastError(); 188 | if (res != NO_ERROR) 189 | return res; 190 | } 191 | *pos = ((Int64)value.HighPart << 32) | value.LowPart; 192 | return 0; 193 | 194 | #else 195 | 196 | int moveMethod; 197 | int res; 198 | switch (origin) 199 | { 200 | case SZ_SEEK_SET: moveMethod = SEEK_SET; break; 201 | case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; 202 | case SZ_SEEK_END: moveMethod = SEEK_END; break; 203 | default: return 1; 204 | } 205 | res = fseek(p->file, (long)*pos, moveMethod); 206 | *pos = ftell(p->file); 207 | return res; 208 | 209 | #endif 210 | } 211 | 212 | WRes File_GetLength(CSzFile *p, UInt64 *length) 213 | { 214 | #ifdef USE_WINDOWS_FILE 215 | 216 | DWORD sizeHigh; 217 | DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); 218 | if (sizeLow == 0xFFFFFFFF) 219 | { 220 | DWORD res = GetLastError(); 221 | if (res != NO_ERROR) 222 | return res; 223 | } 224 | *length = (((UInt64)sizeHigh) << 32) + sizeLow; 225 | return 0; 226 | 227 | #else 228 | 229 | long pos = ftell(p->file); 230 | int res = fseek(p->file, 0, SEEK_END); 231 | *length = ftell(p->file); 232 | fseek(p->file, pos, SEEK_SET); 233 | return res; 234 | 235 | #endif 236 | } 237 | 238 | 239 | /* ---------- FileSeqInStream ---------- */ 240 | 241 | static SRes FileSeqInStream_Read(const ISeqInStream *pp, void *buf, size_t *size) 242 | { 243 | CFileSeqInStream *p = CONTAINER_FROM_VTBL(pp, CFileSeqInStream, vt); 244 | return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; 245 | } 246 | 247 | void FileSeqInStream_CreateVTable(CFileSeqInStream *p) 248 | { 249 | p->vt.Read = FileSeqInStream_Read; 250 | } 251 | 252 | 253 | /* ---------- FileInStream ---------- */ 254 | 255 | static SRes FileInStream_Read(const ISeekInStream *pp, void *buf, size_t *size) 256 | { 257 | CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); 258 | return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; 259 | } 260 | 261 | static SRes FileInStream_Seek(const ISeekInStream *pp, Int64 *pos, ESzSeek origin) 262 | { 263 | CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); 264 | return File_Seek(&p->file, pos, origin); 265 | } 266 | 267 | void FileInStream_CreateVTable(CFileInStream *p) 268 | { 269 | p->vt.Read = FileInStream_Read; 270 | p->vt.Seek = FileInStream_Seek; 271 | } 272 | 273 | 274 | /* ---------- FileOutStream ---------- */ 275 | 276 | static size_t FileOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) 277 | { 278 | CFileOutStream *p = CONTAINER_FROM_VTBL(pp, CFileOutStream, vt); 279 | File_Write(&p->file, data, &size); 280 | return size; 281 | } 282 | 283 | void FileOutStream_CreateVTable(CFileOutStream *p) 284 | { 285 | p->vt.Write = FileOutStream_Write; 286 | } 287 | -------------------------------------------------------------------------------- /lzma/7zFile.h: -------------------------------------------------------------------------------- 1 | /* 7zFile.h -- File IO 2 | 2017-04-03 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __7Z_FILE_H 5 | #define __7Z_FILE_H 6 | 7 | #ifdef _WIN32 8 | //#define USE_WINDOWS_FILE 9 | #endif 10 | 11 | #ifdef USE_WINDOWS_FILE 12 | #include 13 | #else 14 | #include 15 | #endif 16 | 17 | #include "7zTypes.h" 18 | 19 | EXTERN_C_BEGIN 20 | 21 | /* ---------- File ---------- */ 22 | 23 | typedef struct 24 | { 25 | #ifdef USE_WINDOWS_FILE 26 | HANDLE handle; 27 | #else 28 | FILE *file; 29 | #endif 30 | } CSzFile; 31 | 32 | void File_Construct(CSzFile *p); 33 | #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) 34 | WRes InFile_Open(CSzFile *p, const char *name); 35 | WRes OutFile_Open(CSzFile *p, const char *name); 36 | #endif 37 | #ifdef USE_WINDOWS_FILE 38 | WRes InFile_OpenW(CSzFile *p, const WCHAR *name); 39 | WRes OutFile_OpenW(CSzFile *p, const WCHAR *name); 40 | #endif 41 | WRes File_Close(CSzFile *p); 42 | 43 | /* reads max(*size, remain file's size) bytes */ 44 | WRes File_Read(CSzFile *p, void *data, size_t *size); 45 | 46 | /* writes *size bytes */ 47 | WRes File_Write(CSzFile *p, const void *data, size_t *size); 48 | 49 | WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); 50 | WRes File_GetLength(CSzFile *p, UInt64 *length); 51 | 52 | 53 | /* ---------- FileInStream ---------- */ 54 | 55 | typedef struct 56 | { 57 | ISeqInStream vt; 58 | CSzFile file; 59 | } CFileSeqInStream; 60 | 61 | void FileSeqInStream_CreateVTable(CFileSeqInStream *p); 62 | 63 | 64 | typedef struct 65 | { 66 | ISeekInStream vt; 67 | CSzFile file; 68 | } CFileInStream; 69 | 70 | void FileInStream_CreateVTable(CFileInStream *p); 71 | 72 | 73 | typedef struct 74 | { 75 | ISeqOutStream vt; 76 | CSzFile file; 77 | } CFileOutStream; 78 | 79 | void FileOutStream_CreateVTable(CFileOutStream *p); 80 | 81 | EXTERN_C_END 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /lzma/7zTypes.h: -------------------------------------------------------------------------------- 1 | /* 7zTypes.h -- Basic types 2 | 2018-08-04 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __7Z_TYPES_H 5 | #define __7Z_TYPES_H 6 | 7 | #ifdef _WIN32 8 | /* #include */ 9 | #endif 10 | 11 | #include 12 | 13 | #ifndef EXTERN_C_BEGIN 14 | #ifdef __cplusplus 15 | #define EXTERN_C_BEGIN extern "C" { 16 | #define EXTERN_C_END } 17 | #else 18 | #define EXTERN_C_BEGIN 19 | #define EXTERN_C_END 20 | #endif 21 | #endif 22 | 23 | EXTERN_C_BEGIN 24 | 25 | #define SZ_OK 0 26 | 27 | #define SZ_ERROR_DATA 1 28 | #define SZ_ERROR_MEM 2 29 | #define SZ_ERROR_CRC 3 30 | #define SZ_ERROR_UNSUPPORTED 4 31 | #define SZ_ERROR_PARAM 5 32 | #define SZ_ERROR_INPUT_EOF 6 33 | #define SZ_ERROR_OUTPUT_EOF 7 34 | #define SZ_ERROR_READ 8 35 | #define SZ_ERROR_WRITE 9 36 | #define SZ_ERROR_PROGRESS 10 37 | #define SZ_ERROR_FAIL 11 38 | #define SZ_ERROR_THREAD 12 39 | 40 | #define SZ_ERROR_ARCHIVE 16 41 | #define SZ_ERROR_NO_ARCHIVE 17 42 | 43 | typedef int SRes; 44 | 45 | 46 | #ifdef _WIN32 47 | 48 | /* typedef DWORD WRes; */ 49 | typedef unsigned WRes; 50 | #define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x) 51 | 52 | #else 53 | 54 | typedef int WRes; 55 | #define MY__FACILITY_WIN32 7 56 | #define MY__FACILITY__WRes MY__FACILITY_WIN32 57 | #define MY_SRes_HRESULT_FROM_WRes(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (MY__FACILITY__WRes << 16) | 0x80000000))) 58 | 59 | #endif 60 | 61 | 62 | #ifndef RINOK 63 | #define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } 64 | #endif 65 | 66 | typedef unsigned char Byte; 67 | typedef short Int16; 68 | typedef unsigned short UInt16; 69 | 70 | #ifdef _LZMA_UINT32_IS_ULONG 71 | typedef long Int32; 72 | typedef unsigned long UInt32; 73 | #else 74 | typedef int Int32; 75 | typedef unsigned int UInt32; 76 | #endif 77 | 78 | #ifdef _SZ_NO_INT_64 79 | 80 | /* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. 81 | NOTES: Some code will work incorrectly in that case! */ 82 | 83 | typedef long Int64; 84 | typedef unsigned long UInt64; 85 | 86 | #else 87 | 88 | #if defined(_MSC_VER) || defined(__BORLANDC__) 89 | typedef __int64 Int64; 90 | typedef unsigned __int64 UInt64; 91 | #define UINT64_CONST(n) n 92 | #else 93 | typedef long long int Int64; 94 | typedef unsigned long long int UInt64; 95 | #define UINT64_CONST(n) n ## ULL 96 | #endif 97 | 98 | #endif 99 | 100 | #ifdef _LZMA_NO_SYSTEM_SIZE_T 101 | typedef UInt32 SizeT; 102 | #else 103 | typedef size_t SizeT; 104 | #endif 105 | 106 | typedef int BoolInt; 107 | /* typedef BoolInt Bool; */ 108 | #define True 1 109 | #define False 0 110 | 111 | 112 | #ifdef _WIN32 113 | #define MY_STD_CALL __stdcall 114 | #else 115 | #define MY_STD_CALL 116 | #endif 117 | 118 | #ifdef _MSC_VER 119 | 120 | #if _MSC_VER >= 1300 121 | #define MY_NO_INLINE __declspec(noinline) 122 | #else 123 | #define MY_NO_INLINE 124 | #endif 125 | 126 | #define MY_FORCE_INLINE __forceinline 127 | 128 | #define MY_CDECL __cdecl 129 | #define MY_FAST_CALL __fastcall 130 | 131 | #else 132 | 133 | #define MY_NO_INLINE 134 | #define MY_FORCE_INLINE 135 | #define MY_CDECL 136 | #define MY_FAST_CALL 137 | 138 | /* inline keyword : for C++ / C99 */ 139 | 140 | /* GCC, clang: */ 141 | /* 142 | #if defined (__GNUC__) && (__GNUC__ >= 4) 143 | #define MY_FORCE_INLINE __attribute__((always_inline)) 144 | #define MY_NO_INLINE __attribute__((noinline)) 145 | #endif 146 | */ 147 | 148 | #endif 149 | 150 | 151 | /* The following interfaces use first parameter as pointer to structure */ 152 | 153 | typedef struct IByteIn IByteIn; 154 | struct IByteIn 155 | { 156 | Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */ 157 | }; 158 | #define IByteIn_Read(p) (p)->Read(p) 159 | 160 | 161 | typedef struct IByteOut IByteOut; 162 | struct IByteOut 163 | { 164 | void (*Write)(const IByteOut *p, Byte b); 165 | }; 166 | #define IByteOut_Write(p, b) (p)->Write(p, b) 167 | 168 | 169 | typedef struct ISeqInStream ISeqInStream; 170 | struct ISeqInStream 171 | { 172 | SRes (*Read)(const ISeqInStream *p, void *buf, size_t *size); 173 | /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. 174 | (output(*size) < input(*size)) is allowed */ 175 | }; 176 | #define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size) 177 | 178 | /* it can return SZ_ERROR_INPUT_EOF */ 179 | SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size); 180 | SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType); 181 | SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf); 182 | 183 | 184 | typedef struct ISeqOutStream ISeqOutStream; 185 | struct ISeqOutStream 186 | { 187 | size_t (*Write)(const ISeqOutStream *p, const void *buf, size_t size); 188 | /* Returns: result - the number of actually written bytes. 189 | (result < size) means error */ 190 | }; 191 | #define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size) 192 | 193 | typedef enum 194 | { 195 | SZ_SEEK_SET = 0, 196 | SZ_SEEK_CUR = 1, 197 | SZ_SEEK_END = 2 198 | } ESzSeek; 199 | 200 | 201 | typedef struct ISeekInStream ISeekInStream; 202 | struct ISeekInStream 203 | { 204 | SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ 205 | SRes (*Seek)(const ISeekInStream *p, Int64 *pos, ESzSeek origin); 206 | }; 207 | #define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size) 208 | #define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) 209 | 210 | 211 | typedef struct ILookInStream ILookInStream; 212 | struct ILookInStream 213 | { 214 | SRes (*Look)(const ILookInStream *p, const void **buf, size_t *size); 215 | /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. 216 | (output(*size) > input(*size)) is not allowed 217 | (output(*size) < input(*size)) is allowed */ 218 | SRes (*Skip)(const ILookInStream *p, size_t offset); 219 | /* offset must be <= output(*size) of Look */ 220 | 221 | SRes (*Read)(const ILookInStream *p, void *buf, size_t *size); 222 | /* reads directly (without buffer). It's same as ISeqInStream::Read */ 223 | SRes (*Seek)(const ILookInStream *p, Int64 *pos, ESzSeek origin); 224 | }; 225 | 226 | #define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size) 227 | #define ILookInStream_Skip(p, offset) (p)->Skip(p, offset) 228 | #define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size) 229 | #define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) 230 | 231 | 232 | SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size); 233 | SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset); 234 | 235 | /* reads via ILookInStream::Read */ 236 | SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType); 237 | SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size); 238 | 239 | 240 | 241 | typedef struct 242 | { 243 | ILookInStream vt; 244 | const ISeekInStream *realStream; 245 | 246 | size_t pos; 247 | size_t size; /* it's data size */ 248 | 249 | /* the following variables must be set outside */ 250 | Byte *buf; 251 | size_t bufSize; 252 | } CLookToRead2; 253 | 254 | void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead); 255 | 256 | #define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; } 257 | 258 | 259 | typedef struct 260 | { 261 | ISeqInStream vt; 262 | const ILookInStream *realStream; 263 | } CSecToLook; 264 | 265 | void SecToLook_CreateVTable(CSecToLook *p); 266 | 267 | 268 | 269 | typedef struct 270 | { 271 | ISeqInStream vt; 272 | const ILookInStream *realStream; 273 | } CSecToRead; 274 | 275 | void SecToRead_CreateVTable(CSecToRead *p); 276 | 277 | 278 | typedef struct ICompressProgress ICompressProgress; 279 | 280 | struct ICompressProgress 281 | { 282 | SRes (*Progress)(const ICompressProgress *p, UInt64 inSize, UInt64 outSize); 283 | /* Returns: result. (result != SZ_OK) means break. 284 | Value (UInt64)(Int64)-1 for size means unknown value. */ 285 | }; 286 | #define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize) 287 | 288 | 289 | 290 | typedef struct ISzAlloc ISzAlloc; 291 | typedef const ISzAlloc * ISzAllocPtr; 292 | 293 | struct ISzAlloc 294 | { 295 | void *(*Alloc)(ISzAllocPtr p, size_t size); 296 | void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */ 297 | }; 298 | 299 | #define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size) 300 | #define ISzAlloc_Free(p, a) (p)->Free(p, a) 301 | 302 | /* deprecated */ 303 | #define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size) 304 | #define IAlloc_Free(p, a) ISzAlloc_Free(p, a) 305 | 306 | 307 | 308 | 309 | 310 | #ifndef MY_offsetof 311 | #ifdef offsetof 312 | #define MY_offsetof(type, m) offsetof(type, m) 313 | /* 314 | #define MY_offsetof(type, m) FIELD_OFFSET(type, m) 315 | */ 316 | #else 317 | #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m)) 318 | #endif 319 | #endif 320 | 321 | 322 | 323 | #ifndef MY_container_of 324 | 325 | /* 326 | #define MY_container_of(ptr, type, m) container_of(ptr, type, m) 327 | #define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m) 328 | #define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m))) 329 | #define MY_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m)))) 330 | */ 331 | 332 | /* 333 | GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly" 334 | GCC 3.4.4 : classes with constructor 335 | GCC 4.8.1 : classes with non-public variable members" 336 | */ 337 | 338 | #define MY_container_of(ptr, type, m) ((type *)((char *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m))) 339 | 340 | 341 | #endif 342 | 343 | #define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(ptr)) 344 | 345 | /* 346 | #define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) 347 | */ 348 | #define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m) 349 | 350 | #define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) 351 | /* 352 | #define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m) 353 | */ 354 | 355 | 356 | 357 | #ifdef _WIN32 358 | 359 | #define CHAR_PATH_SEPARATOR '\\' 360 | #define WCHAR_PATH_SEPARATOR L'\\' 361 | #define STRING_PATH_SEPARATOR "\\" 362 | #define WSTRING_PATH_SEPARATOR L"\\" 363 | 364 | #else 365 | 366 | #define CHAR_PATH_SEPARATOR '/' 367 | #define WCHAR_PATH_SEPARATOR L'/' 368 | #define STRING_PATH_SEPARATOR "/" 369 | #define WSTRING_PATH_SEPARATOR L"/" 370 | 371 | #endif 372 | 373 | EXTERN_C_END 374 | 375 | #endif 376 | -------------------------------------------------------------------------------- /lzma/Compiler.h: -------------------------------------------------------------------------------- 1 | /* Compiler.h 2 | 2017-04-03 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __7Z_COMPILER_H 5 | #define __7Z_COMPILER_H 6 | 7 | #ifdef _MSC_VER 8 | 9 | #ifdef UNDER_CE 10 | #define RPC_NO_WINDOWS_H 11 | /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ 12 | #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union 13 | #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int 14 | #endif 15 | 16 | #if _MSC_VER >= 1300 17 | #pragma warning(disable : 4996) // This function or variable may be unsafe 18 | #else 19 | #pragma warning(disable : 4511) // copy constructor could not be generated 20 | #pragma warning(disable : 4512) // assignment operator could not be generated 21 | #pragma warning(disable : 4514) // unreferenced inline function has been removed 22 | #pragma warning(disable : 4702) // unreachable code 23 | #pragma warning(disable : 4710) // not inlined 24 | #pragma warning(disable : 4714) // function marked as __forceinline not inlined 25 | #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information 26 | #endif 27 | 28 | #endif 29 | 30 | #define UNUSED_VAR(x) (void)x; 31 | /* #define UNUSED_VAR(x) x=x; */ 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /lzma/LzFind.c: -------------------------------------------------------------------------------- 1 | /* LzFind.c -- Match finder for LZ algorithms 2 | 2018-07-08 : Igor Pavlov : Public domain */ 3 | 4 | #include "Precomp.h" 5 | 6 | #include 7 | 8 | #include "LzFind.h" 9 | #include "LzHash.h" 10 | 11 | #define kEmptyHashValue 0 12 | #define kMaxValForNormalize ((UInt32)0xFFFFFFFF) 13 | #define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ 14 | #define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1)) 15 | #define kMaxHistorySize ((UInt32)7 << 29) 16 | 17 | #define kStartMaxLen 3 18 | 19 | static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc) 20 | { 21 | if (!p->directInput) 22 | { 23 | ISzAlloc_Free(alloc, p->bufferBase); 24 | p->bufferBase = NULL; 25 | } 26 | } 27 | 28 | /* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ 29 | 30 | static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAllocPtr alloc) 31 | { 32 | UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; 33 | if (p->directInput) 34 | { 35 | p->blockSize = blockSize; 36 | return 1; 37 | } 38 | if (!p->bufferBase || p->blockSize != blockSize) 39 | { 40 | LzInWindow_Free(p, alloc); 41 | p->blockSize = blockSize; 42 | p->bufferBase = (Byte *) ISzAlloc_Alloc(alloc, (size_t) blockSize); 43 | } 44 | return (p->bufferBase != NULL); 45 | } 46 | 47 | Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) 48 | { 49 | return p->buffer; 50 | } 51 | 52 | UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) 53 | { 54 | return p->streamPos - p->pos; 55 | } 56 | 57 | void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) 58 | { 59 | p->posLimit -= subValue; 60 | p->pos -= subValue; 61 | p->streamPos -= subValue; 62 | } 63 | 64 | static void MatchFinder_ReadBlock(CMatchFinder *p) 65 | { 66 | if (p->streamEndWasReached || p->result != SZ_OK) 67 | return; 68 | 69 | /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */ 70 | 71 | if (p->directInput) 72 | { 73 | UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos); 74 | if (curSize > p->directInputRem) 75 | curSize = (UInt32) p->directInputRem; 76 | p->directInputRem -= curSize; 77 | p->streamPos += curSize; 78 | if (p->directInputRem == 0) 79 | p->streamEndWasReached = 1; 80 | return; 81 | } 82 | 83 | for (;;) 84 | { 85 | Byte *dest = p->buffer + (p->streamPos - p->pos); 86 | size_t size = (p->bufferBase + p->blockSize - dest); 87 | if (size == 0) 88 | return; 89 | 90 | p->result = ISeqInStream_Read(p->stream, dest, &size); 91 | if (p->result != SZ_OK) 92 | return; 93 | if (size == 0) 94 | { 95 | p->streamEndWasReached = 1; 96 | return; 97 | } 98 | p->streamPos += (UInt32) size; 99 | if (p->streamPos - p->pos > p->keepSizeAfter) 100 | return; 101 | } 102 | } 103 | 104 | void MatchFinder_MoveBlock(CMatchFinder *p) 105 | { 106 | memmove(p->bufferBase, 107 | p->buffer - p->keepSizeBefore, 108 | (size_t) (p->streamPos - p->pos) + p->keepSizeBefore); 109 | p->buffer = p->bufferBase + p->keepSizeBefore; 110 | } 111 | 112 | int MatchFinder_NeedMove(CMatchFinder *p) 113 | { 114 | if (p->directInput) 115 | return 0; 116 | /* if (p->streamEndWasReached) return 0; */ 117 | return ((size_t) (p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); 118 | } 119 | 120 | void MatchFinder_ReadIfRequired(CMatchFinder *p) 121 | { 122 | if (p->streamEndWasReached) 123 | return; 124 | if (p->keepSizeAfter >= p->streamPos - p->pos) 125 | MatchFinder_ReadBlock(p); 126 | } 127 | 128 | static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) 129 | { 130 | if (MatchFinder_NeedMove(p)) 131 | MatchFinder_MoveBlock(p); 132 | MatchFinder_ReadBlock(p); 133 | } 134 | 135 | static void MatchFinder_SetDefaultSettings(CMatchFinder *p) 136 | { 137 | p->cutValue = 32; 138 | p->btMode = 1; 139 | p->numHashBytes = 4; 140 | p->bigHash = 0; 141 | } 142 | 143 | #define kCrcPoly 0xEDB88320 144 | 145 | void MatchFinder_Construct(CMatchFinder *p) 146 | { 147 | unsigned i; 148 | p->bufferBase = NULL; 149 | p->directInput = 0; 150 | p->hash = NULL; 151 | p->expectedDataSize = (UInt64) (Int64) - 1; 152 | MatchFinder_SetDefaultSettings(p); 153 | 154 | for (i = 0; i < 256; i++) 155 | { 156 | UInt32 r = (UInt32) i; 157 | unsigned j; 158 | for (j = 0; j < 8; j++) 159 | r = (r >> 1) ^ (kCrcPoly & ((UInt32) 0 - (r & 1))); 160 | p->crc[i] = r; 161 | } 162 | } 163 | 164 | static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc) 165 | { 166 | ISzAlloc_Free(alloc, p->hash); 167 | p->hash = NULL; 168 | } 169 | 170 | void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc) 171 | { 172 | MatchFinder_FreeThisClassMemory(p, alloc); 173 | LzInWindow_Free(p, alloc); 174 | } 175 | 176 | static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc) 177 | { 178 | size_t sizeInBytes = (size_t) num * sizeof (CLzRef); 179 | if (sizeInBytes / sizeof (CLzRef) != num) 180 | return NULL; 181 | return (CLzRef *) ISzAlloc_Alloc(alloc, sizeInBytes); 182 | } 183 | 184 | int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, 185 | UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, 186 | ISzAllocPtr alloc) 187 | { 188 | UInt32 sizeReserv; 189 | 190 | if (historySize > kMaxHistorySize) 191 | { 192 | MatchFinder_Free(p, alloc); 193 | return 0; 194 | } 195 | 196 | sizeReserv = historySize >> 1; 197 | if (historySize >= ((UInt32) 3 << 30)) sizeReserv = historySize >> 3; 198 | else if (historySize >= ((UInt32) 2 << 30)) sizeReserv = historySize >> 2; 199 | 200 | sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); 201 | 202 | p->keepSizeBefore = historySize + keepAddBufferBefore + 1; 203 | p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; 204 | 205 | /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ 206 | 207 | if (LzInWindow_Create(p, sizeReserv, alloc)) 208 | { 209 | UInt32 newCyclicBufferSize = historySize + 1; 210 | UInt32 hs; 211 | p->matchMaxLen = matchMaxLen; 212 | { 213 | p->fixedHashSize = 0; 214 | if (p->numHashBytes == 2) 215 | hs = (1 << 16) - 1; 216 | else 217 | { 218 | hs = historySize; 219 | if (hs > p->expectedDataSize) 220 | hs = (UInt32) p->expectedDataSize; 221 | if (hs != 0) 222 | hs--; 223 | hs |= (hs >> 1); 224 | hs |= (hs >> 2); 225 | hs |= (hs >> 4); 226 | hs |= (hs >> 8); 227 | hs >>= 1; 228 | hs |= 0xFFFF; /* don't change it! It's required for Deflate */ 229 | if (hs > (1 << 24)) 230 | { 231 | if (p->numHashBytes == 3) 232 | hs = (1 << 24) - 1; 233 | else 234 | hs >>= 1; 235 | /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ 236 | } 237 | } 238 | p->hashMask = hs; 239 | hs++; 240 | if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; 241 | if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; 242 | if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; 243 | hs += p->fixedHashSize; 244 | } 245 | 246 | { 247 | size_t newSize; 248 | size_t numSons; 249 | p->historySize = historySize; 250 | p->hashSizeSum = hs; 251 | p->cyclicBufferSize = newCyclicBufferSize; 252 | 253 | numSons = newCyclicBufferSize; 254 | if (p->btMode) 255 | numSons <<= 1; 256 | newSize = hs + numSons; 257 | 258 | if (p->hash && p->numRefs == newSize) 259 | return 1; 260 | 261 | MatchFinder_FreeThisClassMemory(p, alloc); 262 | p->numRefs = newSize; 263 | p->hash = AllocRefs(newSize, alloc); 264 | 265 | if (p->hash) 266 | { 267 | p->son = p->hash + p->hashSizeSum; 268 | return 1; 269 | } 270 | } 271 | } 272 | 273 | MatchFinder_Free(p, alloc); 274 | return 0; 275 | } 276 | 277 | static void MatchFinder_SetLimits(CMatchFinder *p) 278 | { 279 | UInt32 limit = kMaxValForNormalize - p->pos; 280 | UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; 281 | 282 | if (limit2 < limit) 283 | limit = limit2; 284 | limit2 = p->streamPos - p->pos; 285 | 286 | if (limit2 <= p->keepSizeAfter) 287 | { 288 | if (limit2 > 0) 289 | limit2 = 1; 290 | } 291 | else 292 | limit2 -= p->keepSizeAfter; 293 | 294 | if (limit2 < limit) 295 | limit = limit2; 296 | 297 | { 298 | UInt32 lenLimit = p->streamPos - p->pos; 299 | if (lenLimit > p->matchMaxLen) 300 | lenLimit = p->matchMaxLen; 301 | p->lenLimit = lenLimit; 302 | } 303 | p->posLimit = p->pos + limit; 304 | } 305 | 306 | void MatchFinder_Init_LowHash(CMatchFinder *p) 307 | { 308 | size_t i; 309 | CLzRef *items = p->hash; 310 | size_t numItems = p->fixedHashSize; 311 | for (i = 0; i < numItems; i++) 312 | items[i] = kEmptyHashValue; 313 | } 314 | 315 | void MatchFinder_Init_HighHash(CMatchFinder *p) 316 | { 317 | size_t i; 318 | CLzRef *items = p->hash + p->fixedHashSize; 319 | size_t numItems = (size_t) p->hashMask + 1; 320 | for (i = 0; i < numItems; i++) 321 | items[i] = kEmptyHashValue; 322 | } 323 | 324 | void MatchFinder_Init_3(CMatchFinder *p, int readData) 325 | { 326 | p->cyclicBufferPos = 0; 327 | p->buffer = p->bufferBase; 328 | p->pos = 329 | p->streamPos = p->cyclicBufferSize; 330 | p->result = SZ_OK; 331 | p->streamEndWasReached = 0; 332 | 333 | if (readData) 334 | MatchFinder_ReadBlock(p); 335 | 336 | MatchFinder_SetLimits(p); 337 | } 338 | 339 | void MatchFinder_Init(CMatchFinder *p) 340 | { 341 | MatchFinder_Init_HighHash(p); 342 | MatchFinder_Init_LowHash(p); 343 | MatchFinder_Init_3(p, True); 344 | } 345 | 346 | static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) 347 | { 348 | return (p->pos - p->historySize - 1) & kNormalizeMask; 349 | } 350 | 351 | void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) 352 | { 353 | size_t i; 354 | for (i = 0; i < numItems; i++) 355 | { 356 | UInt32 value = items[i]; 357 | if (value <= subValue) 358 | value = kEmptyHashValue; 359 | else 360 | value -= subValue; 361 | items[i] = value; 362 | } 363 | } 364 | 365 | static void MatchFinder_Normalize(CMatchFinder *p) 366 | { 367 | UInt32 subValue = MatchFinder_GetSubValue(p); 368 | MatchFinder_Normalize3(subValue, p->hash, p->numRefs); 369 | MatchFinder_ReduceOffsets(p, subValue); 370 | } 371 | 372 | MY_NO_INLINE 373 | static void MatchFinder_CheckLimits(CMatchFinder *p) 374 | { 375 | if (p->pos == kMaxValForNormalize) 376 | MatchFinder_Normalize(p); 377 | if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) 378 | MatchFinder_CheckAndMoveAndRead(p); 379 | if (p->cyclicBufferPos == p->cyclicBufferSize) 380 | p->cyclicBufferPos = 0; 381 | MatchFinder_SetLimits(p); 382 | } 383 | 384 | /* 385 | (lenLimit > maxLen) 386 | */ 387 | MY_FORCE_INLINE 388 | static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 389 | UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, 390 | UInt32 *distances, unsigned maxLen) 391 | { 392 | /* 393 | son[_cyclicBufferPos] = curMatch; 394 | for (;;) 395 | { 396 | UInt32 delta = pos - curMatch; 397 | if (cutValue-- == 0 || delta >= _cyclicBufferSize) 398 | return distances; 399 | { 400 | const Byte *pb = cur - delta; 401 | curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; 402 | if (pb[maxLen] == cur[maxLen] && *pb == *cur) 403 | { 404 | UInt32 len = 0; 405 | while (++len != lenLimit) 406 | if (pb[len] != cur[len]) 407 | break; 408 | if (maxLen < len) 409 | { 410 | maxLen = len; 411 | *distances++ = len; 412 | *distances++ = delta - 1; 413 | if (len == lenLimit) 414 | return distances; 415 | } 416 | } 417 | } 418 | } 419 | */ 420 | 421 | const Byte *lim = cur + lenLimit; 422 | son[_cyclicBufferPos] = curMatch; 423 | do 424 | { 425 | UInt32 delta = pos - curMatch; 426 | if (delta >= _cyclicBufferSize) 427 | break; 428 | { 429 | ptrdiff_t diff; 430 | curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; 431 | diff = (ptrdiff_t) 0 - delta; 432 | if (cur[maxLen] == cur[maxLen + diff]) 433 | { 434 | const Byte *c = cur; 435 | while (*c == c[diff]) 436 | { 437 | if (++c == lim) 438 | { 439 | distances[0] = (UInt32) (lim - cur); 440 | distances[1] = delta - 1; 441 | return distances + 2; 442 | } 443 | } 444 | { 445 | unsigned len = (unsigned) (c - cur); 446 | if (maxLen < len) 447 | { 448 | maxLen = len; 449 | distances[0] = (UInt32) len; 450 | distances[1] = delta - 1; 451 | distances += 2; 452 | } 453 | } 454 | } 455 | } 456 | } 457 | while (--cutValue); 458 | 459 | return distances; 460 | } 461 | 462 | MY_FORCE_INLINE 463 | UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 464 | UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, 465 | UInt32 *distances, UInt32 maxLen) 466 | { 467 | CLzRef *ptr0 = son + ((size_t) _cyclicBufferPos << 1) + 1; 468 | CLzRef *ptr1 = son + ((size_t) _cyclicBufferPos << 1); 469 | unsigned len0 = 0, len1 = 0; 470 | for (;;) 471 | { 472 | UInt32 delta = pos - curMatch; 473 | if (cutValue-- == 0 || delta >= _cyclicBufferSize) 474 | { 475 | *ptr0 = *ptr1 = kEmptyHashValue; 476 | return distances; 477 | } 478 | { 479 | CLzRef *pair = son + ((size_t) (_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); 480 | const Byte *pb = cur - delta; 481 | unsigned len = (len0 < len1 ? len0 : len1); 482 | UInt32 pair0 = pair[0]; 483 | if (pb[len] == cur[len]) 484 | { 485 | if (++len != lenLimit && pb[len] == cur[len]) 486 | while (++len != lenLimit) 487 | if (pb[len] != cur[len]) 488 | break; 489 | if (maxLen < len) 490 | { 491 | maxLen = (UInt32) len; 492 | *distances++ = (UInt32) len; 493 | *distances++ = delta - 1; 494 | if (len == lenLimit) 495 | { 496 | *ptr1 = pair0; 497 | *ptr0 = pair[1]; 498 | return distances; 499 | } 500 | } 501 | } 502 | if (pb[len] < cur[len]) 503 | { 504 | *ptr1 = curMatch; 505 | ptr1 = pair + 1; 506 | curMatch = *ptr1; 507 | len1 = len; 508 | } 509 | else 510 | { 511 | *ptr0 = curMatch; 512 | ptr0 = pair; 513 | curMatch = *ptr0; 514 | len0 = len; 515 | } 516 | } 517 | } 518 | } 519 | 520 | static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 521 | UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) 522 | { 523 | CLzRef *ptr0 = son + ((size_t) _cyclicBufferPos << 1) + 1; 524 | CLzRef *ptr1 = son + ((size_t) _cyclicBufferPos << 1); 525 | unsigned len0 = 0, len1 = 0; 526 | for (;;) 527 | { 528 | UInt32 delta = pos - curMatch; 529 | if (cutValue-- == 0 || delta >= _cyclicBufferSize) 530 | { 531 | *ptr0 = *ptr1 = kEmptyHashValue; 532 | return; 533 | } 534 | { 535 | CLzRef *pair = son + ((size_t) (_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); 536 | const Byte *pb = cur - delta; 537 | unsigned len = (len0 < len1 ? len0 : len1); 538 | if (pb[len] == cur[len]) 539 | { 540 | while (++len != lenLimit) 541 | if (pb[len] != cur[len]) 542 | break; 543 | { 544 | if (len == lenLimit) 545 | { 546 | *ptr1 = pair[0]; 547 | *ptr0 = pair[1]; 548 | return; 549 | } 550 | } 551 | } 552 | if (pb[len] < cur[len]) 553 | { 554 | *ptr1 = curMatch; 555 | ptr1 = pair + 1; 556 | curMatch = *ptr1; 557 | len1 = len; 558 | } 559 | else 560 | { 561 | *ptr0 = curMatch; 562 | ptr0 = pair; 563 | curMatch = *ptr0; 564 | len0 = len; 565 | } 566 | } 567 | } 568 | } 569 | 570 | #define MOVE_POS \ 571 | ++p->cyclicBufferPos; \ 572 | p->buffer++; \ 573 | if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); 574 | 575 | #define MOVE_POS_RET MOVE_POS return (UInt32)offset; 576 | 577 | static void MatchFinder_MovePos(CMatchFinder *p) 578 | { 579 | MOVE_POS; 580 | } 581 | 582 | #define GET_MATCHES_HEADER2(minLen, ret_op) \ 583 | unsigned lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \ 584 | lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ 585 | cur = p->buffer; 586 | 587 | #define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) 588 | #define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) 589 | 590 | #define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue 591 | 592 | #define GET_MATCHES_FOOTER(offset, maxLen) \ 593 | offset = (unsigned)(GetMatchesSpec1((UInt32)lenLimit, curMatch, MF_PARAMS(p), \ 594 | distances + offset, (UInt32)maxLen) - distances); MOVE_POS_RET; 595 | 596 | #define SKIP_FOOTER \ 597 | SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; 598 | 599 | #define UPDATE_maxLen { \ 600 | ptrdiff_t diff = (ptrdiff_t)0 - d2; \ 601 | const Byte *c = cur + maxLen; \ 602 | const Byte *lim = cur + lenLimit; \ 603 | for (; c != lim; c++) if (*(c + diff) != *c) break; \ 604 | maxLen = (unsigned)(c - cur); } 605 | 606 | static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) 607 | { 608 | unsigned offset; 609 | GET_MATCHES_HEADER(2) 610 | HASH2_CALC; 611 | curMatch = p->hash[hv]; 612 | p->hash[hv] = p->pos; 613 | offset = 0; 614 | GET_MATCHES_FOOTER(offset, 1) 615 | } 616 | 617 | UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) 618 | { 619 | unsigned offset; 620 | GET_MATCHES_HEADER(3) 621 | HASH_ZIP_CALC; 622 | curMatch = p->hash[hv]; 623 | p->hash[hv] = p->pos; 624 | offset = 0; 625 | GET_MATCHES_FOOTER(offset, 2) 626 | } 627 | 628 | static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) 629 | { 630 | UInt32 h2, d2, pos; 631 | unsigned maxLen, offset; 632 | UInt32 *hash; 633 | GET_MATCHES_HEADER(3) 634 | 635 | HASH3_CALC; 636 | 637 | hash = p->hash; 638 | pos = p->pos; 639 | 640 | d2 = pos - hash[h2]; 641 | 642 | curMatch = (hash + kFix3HashSize)[hv]; 643 | 644 | hash[h2] = pos; 645 | (hash + kFix3HashSize)[hv] = pos; 646 | 647 | maxLen = 2; 648 | offset = 0; 649 | 650 | if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) 651 | { 652 | UPDATE_maxLen 653 | distances[0] = (UInt32) maxLen; 654 | distances[1] = d2 - 1; 655 | offset = 2; 656 | if (maxLen == lenLimit) 657 | { 658 | SkipMatchesSpec((UInt32) lenLimit, curMatch, MF_PARAMS(p)); 659 | MOVE_POS_RET; 660 | } 661 | } 662 | 663 | GET_MATCHES_FOOTER(offset, maxLen) 664 | } 665 | 666 | static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) 667 | { 668 | UInt32 h2, h3, d2, d3, pos; 669 | unsigned maxLen, offset; 670 | UInt32 *hash; 671 | GET_MATCHES_HEADER(4) 672 | 673 | HASH4_CALC; 674 | 675 | hash = p->hash; 676 | pos = p->pos; 677 | 678 | d2 = pos - hash [h2]; 679 | d3 = pos - (hash + kFix3HashSize)[h3]; 680 | 681 | curMatch = (hash + kFix4HashSize)[hv]; 682 | 683 | hash [h2] = pos; 684 | (hash + kFix3HashSize)[h3] = pos; 685 | (hash + kFix4HashSize)[hv] = pos; 686 | 687 | maxLen = 0; 688 | offset = 0; 689 | 690 | if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) 691 | { 692 | maxLen = 2; 693 | distances[0] = 2; 694 | distances[1] = d2 - 1; 695 | offset = 2; 696 | } 697 | 698 | if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) 699 | { 700 | maxLen = 3; 701 | distances[(size_t) offset + 1] = d3 - 1; 702 | offset += 2; 703 | d2 = d3; 704 | } 705 | 706 | if (offset != 0) 707 | { 708 | UPDATE_maxLen 709 | distances[(size_t) offset - 2] = (UInt32) maxLen; 710 | if (maxLen == lenLimit) 711 | { 712 | SkipMatchesSpec((UInt32) lenLimit, curMatch, MF_PARAMS(p)); 713 | MOVE_POS_RET; 714 | } 715 | } 716 | 717 | if (maxLen < 3) 718 | maxLen = 3; 719 | 720 | GET_MATCHES_FOOTER(offset, maxLen) 721 | } 722 | 723 | /* 724 | static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) 725 | { 726 | UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos; 727 | UInt32 *hash; 728 | GET_MATCHES_HEADER(5) 729 | 730 | HASH5_CALC; 731 | 732 | hash = p->hash; 733 | pos = p->pos; 734 | 735 | d2 = pos - hash [h2]; 736 | d3 = pos - (hash + kFix3HashSize)[h3]; 737 | d4 = pos - (hash + kFix4HashSize)[h4]; 738 | 739 | curMatch = (hash + kFix5HashSize)[hv]; 740 | 741 | hash [h2] = pos; 742 | (hash + kFix3HashSize)[h3] = pos; 743 | (hash + kFix4HashSize)[h4] = pos; 744 | (hash + kFix5HashSize)[hv] = pos; 745 | 746 | maxLen = 0; 747 | offset = 0; 748 | 749 | if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) 750 | { 751 | distances[0] = maxLen = 2; 752 | distances[1] = d2 - 1; 753 | offset = 2; 754 | if (*(cur - d2 + 2) == cur[2]) 755 | distances[0] = maxLen = 3; 756 | else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) 757 | { 758 | distances[2] = maxLen = 3; 759 | distances[3] = d3 - 1; 760 | offset = 4; 761 | d2 = d3; 762 | } 763 | } 764 | else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) 765 | { 766 | distances[0] = maxLen = 3; 767 | distances[1] = d3 - 1; 768 | offset = 2; 769 | d2 = d3; 770 | } 771 | 772 | if (d2 != d4 && d4 < p->cyclicBufferSize 773 | && *(cur - d4) == *cur 774 | && *(cur - d4 + 3) == *(cur + 3)) 775 | { 776 | maxLen = 4; 777 | distances[(size_t)offset + 1] = d4 - 1; 778 | offset += 2; 779 | d2 = d4; 780 | } 781 | 782 | if (offset != 0) 783 | { 784 | UPDATE_maxLen 785 | distances[(size_t)offset - 2] = maxLen; 786 | if (maxLen == lenLimit) 787 | { 788 | SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); 789 | MOVE_POS_RET; 790 | } 791 | } 792 | 793 | if (maxLen < 4) 794 | maxLen = 4; 795 | 796 | GET_MATCHES_FOOTER(offset, maxLen) 797 | } 798 | */ 799 | 800 | static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) 801 | { 802 | UInt32 h2, h3, d2, d3, pos; 803 | unsigned maxLen, offset; 804 | UInt32 *hash; 805 | GET_MATCHES_HEADER(4) 806 | 807 | HASH4_CALC; 808 | 809 | hash = p->hash; 810 | pos = p->pos; 811 | 812 | d2 = pos - hash [h2]; 813 | d3 = pos - (hash + kFix3HashSize)[h3]; 814 | curMatch = (hash + kFix4HashSize)[hv]; 815 | 816 | hash [h2] = pos; 817 | (hash + kFix3HashSize)[h3] = pos; 818 | (hash + kFix4HashSize)[hv] = pos; 819 | 820 | maxLen = 0; 821 | offset = 0; 822 | 823 | if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) 824 | { 825 | maxLen = 2; 826 | distances[0] = 2; 827 | distances[1] = d2 - 1; 828 | offset = 2; 829 | } 830 | 831 | if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) 832 | { 833 | maxLen = 3; 834 | distances[(size_t) offset + 1] = d3 - 1; 835 | offset += 2; 836 | d2 = d3; 837 | } 838 | 839 | if (offset != 0) 840 | { 841 | UPDATE_maxLen 842 | distances[(size_t) offset - 2] = (UInt32) maxLen; 843 | if (maxLen == lenLimit) 844 | { 845 | p->son[p->cyclicBufferPos] = curMatch; 846 | MOVE_POS_RET; 847 | } 848 | } 849 | 850 | if (maxLen < 3) 851 | maxLen = 3; 852 | 853 | offset = (unsigned) (Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), 854 | distances + offset, maxLen) - (distances)); 855 | MOVE_POS_RET 856 | } 857 | 858 | /* 859 | static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) 860 | { 861 | UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos 862 | UInt32 *hash; 863 | GET_MATCHES_HEADER(5) 864 | 865 | HASH5_CALC; 866 | 867 | hash = p->hash; 868 | pos = p->pos; 869 | 870 | d2 = pos - hash [h2]; 871 | d3 = pos - (hash + kFix3HashSize)[h3]; 872 | d4 = pos - (hash + kFix4HashSize)[h4]; 873 | 874 | curMatch = (hash + kFix5HashSize)[hv]; 875 | 876 | hash [h2] = pos; 877 | (hash + kFix3HashSize)[h3] = pos; 878 | (hash + kFix4HashSize)[h4] = pos; 879 | (hash + kFix5HashSize)[hv] = pos; 880 | 881 | maxLen = 0; 882 | offset = 0; 883 | 884 | if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) 885 | { 886 | distances[0] = maxLen = 2; 887 | distances[1] = d2 - 1; 888 | offset = 2; 889 | if (*(cur - d2 + 2) == cur[2]) 890 | distances[0] = maxLen = 3; 891 | else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) 892 | { 893 | distances[2] = maxLen = 3; 894 | distances[3] = d3 - 1; 895 | offset = 4; 896 | d2 = d3; 897 | } 898 | } 899 | else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) 900 | { 901 | distances[0] = maxLen = 3; 902 | distances[1] = d3 - 1; 903 | offset = 2; 904 | d2 = d3; 905 | } 906 | 907 | if (d2 != d4 && d4 < p->cyclicBufferSize 908 | && *(cur - d4) == *cur 909 | && *(cur - d4 + 3) == *(cur + 3)) 910 | { 911 | maxLen = 4; 912 | distances[(size_t)offset + 1] = d4 - 1; 913 | offset += 2; 914 | d2 = d4; 915 | } 916 | 917 | if (offset != 0) 918 | { 919 | UPDATE_maxLen 920 | distances[(size_t)offset - 2] = maxLen; 921 | if (maxLen == lenLimit) 922 | { 923 | p->son[p->cyclicBufferPos] = curMatch; 924 | MOVE_POS_RET; 925 | } 926 | } 927 | 928 | if (maxLen < 4) 929 | maxLen = 4; 930 | 931 | offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), 932 | distances + offset, maxLen) - (distances)); 933 | MOVE_POS_RET 934 | } 935 | */ 936 | 937 | UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) 938 | { 939 | unsigned offset; 940 | GET_MATCHES_HEADER(3) 941 | HASH_ZIP_CALC; 942 | curMatch = p->hash[hv]; 943 | p->hash[hv] = p->pos; 944 | offset = (unsigned) (Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), 945 | distances, 2) - (distances)); 946 | MOVE_POS_RET 947 | } 948 | 949 | static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) 950 | { 951 | do 952 | { 953 | SKIP_HEADER(2) 954 | HASH2_CALC; 955 | curMatch = p->hash[hv]; 956 | p->hash[hv] = p->pos; 957 | SKIP_FOOTER 958 | } 959 | while (--num != 0); 960 | } 961 | 962 | void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) 963 | { 964 | do 965 | { 966 | SKIP_HEADER(3) 967 | HASH_ZIP_CALC; 968 | curMatch = p->hash[hv]; 969 | p->hash[hv] = p->pos; 970 | SKIP_FOOTER 971 | } 972 | while (--num != 0); 973 | } 974 | 975 | static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) 976 | { 977 | do 978 | { 979 | UInt32 h2; 980 | UInt32 *hash; 981 | SKIP_HEADER(3) 982 | HASH3_CALC; 983 | hash = p->hash; 984 | curMatch = (hash + kFix3HashSize)[hv]; 985 | hash[h2] = 986 | (hash + kFix3HashSize)[hv] = p->pos; 987 | SKIP_FOOTER 988 | } 989 | while (--num != 0); 990 | } 991 | 992 | static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) 993 | { 994 | do 995 | { 996 | UInt32 h2, h3; 997 | UInt32 *hash; 998 | SKIP_HEADER(4) 999 | HASH4_CALC; 1000 | hash = p->hash; 1001 | curMatch = (hash + kFix4HashSize)[hv]; 1002 | hash [h2] = 1003 | (hash + kFix3HashSize)[h3] = 1004 | (hash + kFix4HashSize)[hv] = p->pos; 1005 | SKIP_FOOTER 1006 | } 1007 | while (--num != 0); 1008 | } 1009 | 1010 | /* 1011 | static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) 1012 | { 1013 | do 1014 | { 1015 | UInt32 h2, h3, h4; 1016 | UInt32 *hash; 1017 | SKIP_HEADER(5) 1018 | HASH5_CALC; 1019 | hash = p->hash; 1020 | curMatch = (hash + kFix5HashSize)[hv]; 1021 | hash [h2] = 1022 | (hash + kFix3HashSize)[h3] = 1023 | (hash + kFix4HashSize)[h4] = 1024 | (hash + kFix5HashSize)[hv] = p->pos; 1025 | SKIP_FOOTER 1026 | } 1027 | while (--num != 0); 1028 | } 1029 | */ 1030 | 1031 | static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) 1032 | { 1033 | do 1034 | { 1035 | UInt32 h2, h3; 1036 | UInt32 *hash; 1037 | SKIP_HEADER(4) 1038 | HASH4_CALC; 1039 | hash = p->hash; 1040 | curMatch = (hash + kFix4HashSize)[hv]; 1041 | hash [h2] = 1042 | (hash + kFix3HashSize)[h3] = 1043 | (hash + kFix4HashSize)[hv] = p->pos; 1044 | p->son[p->cyclicBufferPos] = curMatch; 1045 | MOVE_POS 1046 | } 1047 | while (--num != 0); 1048 | } 1049 | 1050 | /* 1051 | static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) 1052 | { 1053 | do 1054 | { 1055 | UInt32 h2, h3, h4; 1056 | UInt32 *hash; 1057 | SKIP_HEADER(5) 1058 | HASH5_CALC; 1059 | hash = p->hash; 1060 | curMatch = hash + kFix5HashSize)[hv]; 1061 | hash [h2] = 1062 | (hash + kFix3HashSize)[h3] = 1063 | (hash + kFix4HashSize)[h4] = 1064 | (hash + kFix5HashSize)[hv] = p->pos; 1065 | p->son[p->cyclicBufferPos] = curMatch; 1066 | MOVE_POS 1067 | } 1068 | while (--num != 0); 1069 | } 1070 | */ 1071 | 1072 | void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) 1073 | { 1074 | do 1075 | { 1076 | SKIP_HEADER(3) 1077 | HASH_ZIP_CALC; 1078 | curMatch = p->hash[hv]; 1079 | p->hash[hv] = p->pos; 1080 | p->son[p->cyclicBufferPos] = curMatch; 1081 | MOVE_POS 1082 | } 1083 | while (--num != 0); 1084 | } 1085 | 1086 | void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) 1087 | { 1088 | vTable->Init = (Mf_Init_Func) MatchFinder_Init; 1089 | vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func) MatchFinder_GetNumAvailableBytes; 1090 | vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func) MatchFinder_GetPointerToCurrentPos; 1091 | if (!p->btMode) 1092 | { 1093 | /* if (p->numHashBytes <= 4) */ 1094 | { 1095 | vTable->GetMatches = (Mf_GetMatches_Func) Hc4_MatchFinder_GetMatches; 1096 | vTable->Skip = (Mf_Skip_Func) Hc4_MatchFinder_Skip; 1097 | } 1098 | /* 1099 | else 1100 | { 1101 | vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches; 1102 | vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip; 1103 | } 1104 | */ 1105 | } 1106 | else if (p->numHashBytes == 2) 1107 | { 1108 | vTable->GetMatches = (Mf_GetMatches_Func) Bt2_MatchFinder_GetMatches; 1109 | vTable->Skip = (Mf_Skip_Func) Bt2_MatchFinder_Skip; 1110 | } 1111 | else if (p->numHashBytes == 3) 1112 | { 1113 | vTable->GetMatches = (Mf_GetMatches_Func) Bt3_MatchFinder_GetMatches; 1114 | vTable->Skip = (Mf_Skip_Func) Bt3_MatchFinder_Skip; 1115 | } 1116 | else /* if (p->numHashBytes == 4) */ 1117 | { 1118 | vTable->GetMatches = (Mf_GetMatches_Func) Bt4_MatchFinder_GetMatches; 1119 | vTable->Skip = (Mf_Skip_Func) Bt4_MatchFinder_Skip; 1120 | } 1121 | /* 1122 | else 1123 | { 1124 | vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches; 1125 | vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip; 1126 | } 1127 | */ 1128 | } 1129 | -------------------------------------------------------------------------------- /lzma/LzFind.h: -------------------------------------------------------------------------------- 1 | /* LzFind.h -- Match finder for LZ algorithms 2 | 2017-06-10 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __LZ_FIND_H 5 | #define __LZ_FIND_H 6 | 7 | #include "7zTypes.h" 8 | 9 | EXTERN_C_BEGIN 10 | 11 | typedef UInt32 CLzRef; 12 | 13 | typedef struct _CMatchFinder 14 | { 15 | Byte *buffer; 16 | UInt32 pos; 17 | UInt32 posLimit; 18 | UInt32 streamPos; 19 | UInt32 lenLimit; 20 | 21 | UInt32 cyclicBufferPos; 22 | UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ 23 | 24 | Byte streamEndWasReached; 25 | Byte btMode; 26 | Byte bigHash; 27 | Byte directInput; 28 | 29 | UInt32 matchMaxLen; 30 | CLzRef *hash; 31 | CLzRef *son; 32 | UInt32 hashMask; 33 | UInt32 cutValue; 34 | 35 | Byte *bufferBase; 36 | ISeqInStream *stream; 37 | 38 | UInt32 blockSize; 39 | UInt32 keepSizeBefore; 40 | UInt32 keepSizeAfter; 41 | 42 | UInt32 numHashBytes; 43 | size_t directInputRem; 44 | UInt32 historySize; 45 | UInt32 fixedHashSize; 46 | UInt32 hashSizeSum; 47 | SRes result; 48 | UInt32 crc[256]; 49 | size_t numRefs; 50 | 51 | UInt64 expectedDataSize; 52 | } CMatchFinder; 53 | 54 | #define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) 55 | 56 | #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) 57 | 58 | #define Inline_MatchFinder_IsFinishedOK(p) \ 59 | ((p)->streamEndWasReached \ 60 | && (p)->streamPos == (p)->pos \ 61 | && (!(p)->directInput || (p)->directInputRem == 0)) 62 | 63 | int MatchFinder_NeedMove(CMatchFinder *p); 64 | Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); 65 | void MatchFinder_MoveBlock(CMatchFinder *p); 66 | void MatchFinder_ReadIfRequired(CMatchFinder *p); 67 | 68 | void MatchFinder_Construct(CMatchFinder *p); 69 | 70 | /* Conditions: 71 | historySize <= 3 GB 72 | keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB 73 | */ 74 | int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, 75 | UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, 76 | ISzAllocPtr alloc); 77 | void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc); 78 | void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems); 79 | void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); 80 | 81 | UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, 82 | UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, 83 | UInt32 *distances, UInt32 maxLen); 84 | 85 | /* 86 | Conditions: 87 | Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. 88 | Mf_GetPointerToCurrentPos_Func's result must be used only before any other function 89 | */ 90 | 91 | typedef void (*Mf_Init_Func)(void *object); 92 | typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); 93 | typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); 94 | typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); 95 | typedef void (*Mf_Skip_Func)(void *object, UInt32); 96 | 97 | typedef struct _IMatchFinder 98 | { 99 | Mf_Init_Func Init; 100 | Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; 101 | Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; 102 | Mf_GetMatches_Func GetMatches; 103 | Mf_Skip_Func Skip; 104 | } IMatchFinder; 105 | 106 | void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); 107 | 108 | void MatchFinder_Init_LowHash(CMatchFinder *p); 109 | void MatchFinder_Init_HighHash(CMatchFinder *p); 110 | void MatchFinder_Init_3(CMatchFinder *p, int readData); 111 | void MatchFinder_Init(CMatchFinder *p); 112 | 113 | UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); 114 | UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); 115 | 116 | void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); 117 | void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); 118 | 119 | EXTERN_C_END 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /lzma/LzHash.h: -------------------------------------------------------------------------------- 1 | /* LzHash.h -- HASH functions for LZ algorithms 2 | 2015-04-12 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __LZ_HASH_H 5 | #define __LZ_HASH_H 6 | 7 | #define kHash2Size (1 << 10) 8 | #define kHash3Size (1 << 16) 9 | #define kHash4Size (1 << 20) 10 | 11 | #define kFix3HashSize (kHash2Size) 12 | #define kFix4HashSize (kHash2Size + kHash3Size) 13 | #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) 14 | 15 | #define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8); 16 | 17 | #define HASH3_CALC { \ 18 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ 19 | h2 = temp & (kHash2Size - 1); \ 20 | hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } 21 | 22 | #define HASH4_CALC { \ 23 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ 24 | h2 = temp & (kHash2Size - 1); \ 25 | temp ^= ((UInt32)cur[2] << 8); \ 26 | h3 = temp & (kHash3Size - 1); \ 27 | hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; } 28 | 29 | #define HASH5_CALC { \ 30 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ 31 | h2 = temp & (kHash2Size - 1); \ 32 | temp ^= ((UInt32)cur[2] << 8); \ 33 | h3 = temp & (kHash3Size - 1); \ 34 | temp ^= (p->crc[cur[3]] << 5); \ 35 | h4 = temp & (kHash4Size - 1); \ 36 | hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; } 37 | 38 | /* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ 39 | #define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; 40 | 41 | 42 | #define MT_HASH2_CALC \ 43 | h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); 44 | 45 | #define MT_HASH3_CALC { \ 46 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ 47 | h2 = temp & (kHash2Size - 1); \ 48 | h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } 49 | 50 | #define MT_HASH4_CALC { \ 51 | UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ 52 | h2 = temp & (kHash2Size - 1); \ 53 | temp ^= ((UInt32)cur[2] << 8); \ 54 | h3 = temp & (kHash3Size - 1); \ 55 | h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /lzma/LzmaDec.c: -------------------------------------------------------------------------------- 1 | /* LzmaDec.c -- LZMA Decoder 2 | 2018-07-04 : Igor Pavlov : Public domain */ 3 | 4 | #include "Precomp.h" 5 | 6 | #include 7 | 8 | /* #include "CpuArch.h" */ 9 | #include "LzmaDec.h" 10 | 11 | #define kNumTopBits 24 12 | #define kTopValue ((UInt32)1 << kNumTopBits) 13 | 14 | #define kNumBitModelTotalBits 11 15 | #define kBitModelTotal (1 << kNumBitModelTotalBits) 16 | #define kNumMoveBits 5 17 | 18 | #define RC_INIT_SIZE 5 19 | 20 | #define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } 21 | 22 | #define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) 23 | #define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); 24 | #define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); 25 | #define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ 26 | { UPDATE_0(p); i = (i + i); A0; } else \ 27 | { UPDATE_1(p); i = (i + i) + 1; A1; } 28 | 29 | #define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); } 30 | 31 | #define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \ 32 | { UPDATE_0(p + i); A0; } else \ 33 | { UPDATE_1(p + i); A1; } 34 | #define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; ) 35 | #define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; ) 36 | #define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; ) 37 | 38 | #define TREE_DECODE(probs, limit, i) \ 39 | { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } 40 | 41 | /* #define _LZMA_SIZE_OPT */ 42 | 43 | #ifdef _LZMA_SIZE_OPT 44 | #define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) 45 | #else 46 | #define TREE_6_DECODE(probs, i) \ 47 | { i = 1; \ 48 | TREE_GET_BIT(probs, i); \ 49 | TREE_GET_BIT(probs, i); \ 50 | TREE_GET_BIT(probs, i); \ 51 | TREE_GET_BIT(probs, i); \ 52 | TREE_GET_BIT(probs, i); \ 53 | TREE_GET_BIT(probs, i); \ 54 | i -= 0x40; } 55 | #endif 56 | 57 | #define NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol) 58 | #define MATCHED_LITER_DEC \ 59 | matchByte += matchByte; \ 60 | bit = offs; \ 61 | offs &= matchByte; \ 62 | probLit = prob + (offs + bit + symbol); \ 63 | GET_BIT2(probLit, symbol, offs ^= bit; , ;) 64 | 65 | 66 | 67 | #define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } 68 | 69 | #define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) 70 | #define UPDATE_0_CHECK range = bound; 71 | #define UPDATE_1_CHECK range -= bound; code -= bound; 72 | #define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ 73 | { UPDATE_0_CHECK; i = (i + i); A0; } else \ 74 | { UPDATE_1_CHECK; i = (i + i) + 1; A1; } 75 | #define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) 76 | #define TREE_DECODE_CHECK(probs, limit, i) \ 77 | { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } 78 | 79 | 80 | #define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \ 81 | { UPDATE_0_CHECK; i += m; m += m; } else \ 82 | { UPDATE_1_CHECK; m += m; i += m; } 83 | 84 | 85 | #define kNumPosBitsMax 4 86 | #define kNumPosStatesMax (1 << kNumPosBitsMax) 87 | 88 | #define kLenNumLowBits 3 89 | #define kLenNumLowSymbols (1 << kLenNumLowBits) 90 | #define kLenNumHighBits 8 91 | #define kLenNumHighSymbols (1 << kLenNumHighBits) 92 | 93 | #define LenLow 0 94 | #define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits)) 95 | #define kNumLenProbs (LenHigh + kLenNumHighSymbols) 96 | 97 | #define LenChoice LenLow 98 | #define LenChoice2 (LenLow + (1 << kLenNumLowBits)) 99 | 100 | #define kNumStates 12 101 | #define kNumStates2 16 102 | #define kNumLitStates 7 103 | 104 | #define kStartPosModelIndex 4 105 | #define kEndPosModelIndex 14 106 | #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) 107 | 108 | #define kNumPosSlotBits 6 109 | #define kNumLenToPosStates 4 110 | 111 | #define kNumAlignBits 4 112 | #define kAlignTableSize (1 << kNumAlignBits) 113 | 114 | #define kMatchMinLen 2 115 | #define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols) 116 | 117 | /* External ASM code needs same CLzmaProb array layout. So don't change it. */ 118 | 119 | /* (probs_1664) is faster and better for code size at some platforms */ 120 | /* 121 | #ifdef MY_CPU_X86_OR_AMD64 122 | */ 123 | #define kStartOffset 1664 124 | #define GET_PROBS p->probs_1664 125 | /* 126 | #define GET_PROBS p->probs + kStartOffset 127 | #else 128 | #define kStartOffset 0 129 | #define GET_PROBS p->probs 130 | #endif 131 | */ 132 | 133 | #define SpecPos (-kStartOffset) 134 | #define IsRep0Long (SpecPos + kNumFullDistances) 135 | #define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax)) 136 | #define LenCoder (RepLenCoder + kNumLenProbs) 137 | #define IsMatch (LenCoder + kNumLenProbs) 138 | #define Align (IsMatch + (kNumStates2 << kNumPosBitsMax)) 139 | #define IsRep (Align + kAlignTableSize) 140 | #define IsRepG0 (IsRep + kNumStates) 141 | #define IsRepG1 (IsRepG0 + kNumStates) 142 | #define IsRepG2 (IsRepG1 + kNumStates) 143 | #define PosSlot (IsRepG2 + kNumStates) 144 | #define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) 145 | #define NUM_BASE_PROBS (Literal + kStartOffset) 146 | 147 | #if Align != 0 && kStartOffset != 0 148 | #error Stop_Compiling_Bad_LZMA_kAlign 149 | #endif 150 | 151 | #if NUM_BASE_PROBS != 1984 152 | #error Stop_Compiling_Bad_LZMA_PROBS 153 | #endif 154 | 155 | 156 | #define LZMA_LIT_SIZE 0x300 157 | 158 | #define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) 159 | 160 | 161 | #define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4) 162 | #define COMBINED_PS_STATE (posState + state) 163 | #define GET_LEN_STATE (posState) 164 | 165 | #define LZMA_DIC_MIN (1 << 12) 166 | 167 | /* 168 | p->remainLen : shows status of LZMA decoder: 169 | < kMatchSpecLenStart : normal remain 170 | = kMatchSpecLenStart : finished 171 | = kMatchSpecLenStart + 1 : need init range coder 172 | = kMatchSpecLenStart + 2 : need init range coder and state 173 | */ 174 | 175 | /* ---------- LZMA_DECODE_REAL ---------- */ 176 | /* 177 | LzmaDec_DecodeReal_3() can be implemented in external ASM file. 178 | 3 - is the code compatibility version of that function for check at link time. 179 | */ 180 | 181 | #define LZMA_DECODE_REAL LzmaDec_DecodeReal_3 182 | 183 | /* 184 | LZMA_DECODE_REAL() 185 | In: 186 | RangeCoder is normalized 187 | if (p->dicPos == limit) 188 | { 189 | LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases. 190 | So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol 191 | is not END_OF_PAYALOAD_MARKER, then function returns error code. 192 | } 193 | 194 | Processing: 195 | first LZMA symbol will be decoded in any case 196 | All checks for limits are at the end of main loop, 197 | It will decode new LZMA-symbols while (p->buf < bufLimit && dicPos < limit), 198 | RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked. 199 | 200 | Out: 201 | RangeCoder is normalized 202 | Result: 203 | SZ_OK - OK 204 | SZ_ERROR_DATA - Error 205 | p->remainLen: 206 | < kMatchSpecLenStart : normal remain 207 | = kMatchSpecLenStart : finished 208 | */ 209 | 210 | 211 | #ifdef _LZMA_DEC_OPT 212 | 213 | int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit); 214 | 215 | #else 216 | 217 | static 218 | int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit) 219 | { 220 | CLzmaProb *probs = GET_PROBS; 221 | unsigned state = (unsigned) p->state; 222 | UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; 223 | unsigned pbMask = ((unsigned) 1 << (p->prop.pb)) - 1; 224 | unsigned lc = p->prop.lc; 225 | unsigned lpMask = ((unsigned) 0x100 << p->prop.lp) - ((unsigned) 0x100 >> lc); 226 | 227 | Byte *dic = p->dic; 228 | SizeT dicBufSize = p->dicBufSize; 229 | SizeT dicPos = p->dicPos; 230 | 231 | UInt32 processedPos = p->processedPos; 232 | UInt32 checkDicSize = p->checkDicSize; 233 | unsigned len = 0; 234 | 235 | const Byte *buf = p->buf; 236 | UInt32 range = p->range; 237 | UInt32 code = p->code; 238 | 239 | do 240 | { 241 | CLzmaProb *prob; 242 | UInt32 bound; 243 | unsigned ttt; 244 | unsigned posState = CALC_POS_STATE(processedPos, pbMask); 245 | 246 | prob = probs + IsMatch + COMBINED_PS_STATE; 247 | 248 | IF_BIT_0(prob) 249 | { 250 | unsigned symbol; 251 | UPDATE_0(prob); 252 | prob = probs + Literal; 253 | if (processedPos != 0 || checkDicSize != 0) 254 | prob += (UInt32) 3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc); 255 | processedPos++; 256 | 257 | if (state < kNumLitStates) 258 | { 259 | state -= (state < 4) ? state : 3; 260 | symbol = 1; 261 | #ifdef _LZMA_SIZE_OPT 262 | do 263 | { 264 | NORMAL_LITER_DEC 265 | } 266 | while (symbol < 0x100); 267 | #else 268 | NORMAL_LITER_DEC 269 | NORMAL_LITER_DEC 270 | NORMAL_LITER_DEC 271 | NORMAL_LITER_DEC 272 | NORMAL_LITER_DEC 273 | NORMAL_LITER_DEC 274 | NORMAL_LITER_DEC 275 | NORMAL_LITER_DEC 276 | #endif 277 | } 278 | else 279 | { 280 | unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; 281 | unsigned offs = 0x100; 282 | state -= (state < 10) ? 3 : 6; 283 | symbol = 1; 284 | #ifdef _LZMA_SIZE_OPT 285 | do 286 | { 287 | unsigned bit; 288 | CLzmaProb *probLit; 289 | MATCHED_LITER_DEC 290 | } 291 | while (symbol < 0x100); 292 | #else 293 | { 294 | unsigned bit; 295 | CLzmaProb *probLit; 296 | MATCHED_LITER_DEC 297 | MATCHED_LITER_DEC 298 | MATCHED_LITER_DEC 299 | MATCHED_LITER_DEC 300 | MATCHED_LITER_DEC 301 | MATCHED_LITER_DEC 302 | MATCHED_LITER_DEC 303 | MATCHED_LITER_DEC 304 | } 305 | #endif 306 | } 307 | 308 | dic[dicPos++] = (Byte) symbol; 309 | continue; 310 | } 311 | 312 | { 313 | UPDATE_1(prob); 314 | prob = probs + IsRep + state; 315 | 316 | IF_BIT_0(prob) 317 | { 318 | UPDATE_0(prob); 319 | state += kNumStates; 320 | prob = probs + LenCoder; 321 | } 322 | else 323 | { 324 | UPDATE_1(prob); 325 | /* 326 | // that case was checked before with kBadRepCode 327 | if (checkDicSize == 0 && processedPos == 0) 328 | return SZ_ERROR_DATA; 329 | */ 330 | prob = probs + IsRepG0 + state; 331 | 332 | IF_BIT_0(prob) 333 | { 334 | UPDATE_0(prob); 335 | prob = probs + IsRep0Long + COMBINED_PS_STATE; 336 | 337 | IF_BIT_0(prob) 338 | { 339 | UPDATE_0(prob); 340 | dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; 341 | dicPos++; 342 | processedPos++; 343 | state = state < kNumLitStates ? 9 : 11; 344 | continue; 345 | } 346 | UPDATE_1(prob); 347 | } 348 | else 349 | { 350 | UInt32 distance; 351 | UPDATE_1(prob); 352 | prob = probs + IsRepG1 + state; 353 | 354 | IF_BIT_0(prob) 355 | { 356 | UPDATE_0(prob); 357 | distance = rep1; 358 | } 359 | else 360 | { 361 | UPDATE_1(prob); 362 | prob = probs + IsRepG2 + state; 363 | 364 | IF_BIT_0(prob) 365 | { 366 | UPDATE_0(prob); 367 | distance = rep2; 368 | } 369 | else 370 | { 371 | UPDATE_1(prob); 372 | distance = rep3; 373 | rep3 = rep2; 374 | } 375 | rep2 = rep1; 376 | } 377 | rep1 = rep0; 378 | rep0 = distance; 379 | } 380 | state = state < kNumLitStates ? 8 : 11; 381 | prob = probs + RepLenCoder; 382 | } 383 | 384 | #ifdef _LZMA_SIZE_OPT 385 | { 386 | unsigned lim, offset; 387 | CLzmaProb *probLen = prob + LenChoice; 388 | 389 | IF_BIT_0(probLen) 390 | { 391 | UPDATE_0(probLen); 392 | probLen = prob + LenLow + GET_LEN_STATE; 393 | offset = 0; 394 | lim = (1 << kLenNumLowBits); 395 | } 396 | else 397 | { 398 | UPDATE_1(probLen); 399 | probLen = prob + LenChoice2; 400 | 401 | IF_BIT_0(probLen) 402 | { 403 | UPDATE_0(probLen); 404 | probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); 405 | offset = kLenNumLowSymbols; 406 | lim = (1 << kLenNumLowBits); 407 | } 408 | else 409 | { 410 | UPDATE_1(probLen); 411 | probLen = prob + LenHigh; 412 | offset = kLenNumLowSymbols * 2; 413 | lim = (1 << kLenNumHighBits); 414 | } 415 | } 416 | TREE_DECODE(probLen, lim, len); 417 | len += offset; 418 | } 419 | #else 420 | { 421 | CLzmaProb *probLen = prob + LenChoice; 422 | 423 | IF_BIT_0(probLen) 424 | { 425 | UPDATE_0(probLen); 426 | probLen = prob + LenLow + GET_LEN_STATE; 427 | len = 1; 428 | TREE_GET_BIT(probLen, len); 429 | TREE_GET_BIT(probLen, len); 430 | TREE_GET_BIT(probLen, len); 431 | len -= 8; 432 | } 433 | else 434 | { 435 | UPDATE_1(probLen); 436 | probLen = prob + LenChoice2; 437 | 438 | IF_BIT_0(probLen) 439 | { 440 | UPDATE_0(probLen); 441 | probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); 442 | len = 1; 443 | TREE_GET_BIT(probLen, len); 444 | TREE_GET_BIT(probLen, len); 445 | TREE_GET_BIT(probLen, len); 446 | } 447 | else 448 | { 449 | UPDATE_1(probLen); 450 | probLen = prob + LenHigh; 451 | TREE_DECODE(probLen, (1 << kLenNumHighBits), len); 452 | len += kLenNumLowSymbols * 2; 453 | } 454 | } 455 | } 456 | #endif 457 | 458 | if (state >= kNumStates) 459 | { 460 | UInt32 distance; 461 | prob = probs + PosSlot + 462 | ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); 463 | TREE_6_DECODE(prob, distance); 464 | if (distance >= kStartPosModelIndex) 465 | { 466 | unsigned posSlot = (unsigned) distance; 467 | unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); 468 | distance = (2 | (distance & 1)); 469 | if (posSlot < kEndPosModelIndex) 470 | { 471 | distance <<= numDirectBits; 472 | prob = probs + SpecPos; 473 | { 474 | UInt32 m = 1; 475 | distance++; 476 | do 477 | { 478 | REV_BIT_VAR(prob, distance, m); 479 | } 480 | while (--numDirectBits); 481 | distance -= m; 482 | } 483 | } 484 | else 485 | { 486 | numDirectBits -= kNumAlignBits; 487 | do 488 | { 489 | NORMALIZE 490 | range >>= 1; 491 | 492 | { 493 | UInt32 t; 494 | code -= range; 495 | t = (0 - ((UInt32) code >> 31)); /* (UInt32)((Int32)code >> 31) */ 496 | distance = (distance << 1) + (t + 1); 497 | code += range & t; 498 | } 499 | /* 500 | distance <<= 1; 501 | if (code >= range) 502 | { 503 | code -= range; 504 | distance |= 1; 505 | } 506 | */ 507 | } 508 | while (--numDirectBits); 509 | prob = probs + Align; 510 | distance <<= kNumAlignBits; 511 | { 512 | unsigned i = 1; 513 | REV_BIT_CONST(prob, i, 1); 514 | REV_BIT_CONST(prob, i, 2); 515 | REV_BIT_CONST(prob, i, 4); 516 | REV_BIT_LAST(prob, i, 8); 517 | distance |= i; 518 | } 519 | if (distance == (UInt32) 0xFFFFFFFF) 520 | { 521 | len = kMatchSpecLenStart; 522 | state -= kNumStates; 523 | break; 524 | } 525 | } 526 | } 527 | 528 | rep3 = rep2; 529 | rep2 = rep1; 530 | rep1 = rep0; 531 | rep0 = distance + 1; 532 | state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; 533 | if (distance >= (checkDicSize == 0 ? processedPos : checkDicSize)) 534 | { 535 | p->dicPos = dicPos; 536 | return SZ_ERROR_DATA; 537 | } 538 | } 539 | 540 | len += kMatchMinLen; 541 | 542 | { 543 | SizeT rem; 544 | unsigned curLen; 545 | SizeT pos; 546 | 547 | if ((rem = limit - dicPos) == 0) 548 | { 549 | p->dicPos = dicPos; 550 | return SZ_ERROR_DATA; 551 | } 552 | 553 | curLen = ((rem < len) ? (unsigned) rem : len); 554 | pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); 555 | 556 | processedPos += (UInt32) curLen; 557 | 558 | len -= curLen; 559 | if (curLen <= dicBufSize - pos) 560 | { 561 | Byte *dest = dic + dicPos; 562 | ptrdiff_t src = (ptrdiff_t) pos - (ptrdiff_t) dicPos; 563 | const Byte *lim = dest + curLen; 564 | dicPos += (SizeT) curLen; 565 | do 566 | *(dest) = (Byte) * (dest + src); 567 | while (++dest != lim); 568 | } 569 | else 570 | { 571 | do 572 | { 573 | dic[dicPos++] = dic[pos]; 574 | if (++pos == dicBufSize) 575 | pos = 0; 576 | } 577 | while (--curLen != 0); 578 | } 579 | } 580 | } 581 | } 582 | while (dicPos < limit && buf < bufLimit); 583 | 584 | NORMALIZE; 585 | 586 | p->buf = buf; 587 | p->range = range; 588 | p->code = code; 589 | p->remainLen = (UInt32) len; 590 | p->dicPos = dicPos; 591 | p->processedPos = processedPos; 592 | p->reps[0] = rep0; 593 | p->reps[1] = rep1; 594 | p->reps[2] = rep2; 595 | p->reps[3] = rep3; 596 | p->state = (UInt32) state; 597 | 598 | return SZ_OK; 599 | } 600 | #endif 601 | 602 | static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) 603 | { 604 | if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) 605 | { 606 | Byte *dic = p->dic; 607 | SizeT dicPos = p->dicPos; 608 | SizeT dicBufSize = p->dicBufSize; 609 | unsigned len = (unsigned) p->remainLen; 610 | SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ 611 | SizeT rem = limit - dicPos; 612 | if (rem < len) 613 | len = (unsigned)(rem); 614 | 615 | if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) 616 | p->checkDicSize = p->prop.dicSize; 617 | 618 | p->processedPos += (UInt32) len; 619 | p->remainLen -= (UInt32) len; 620 | while (len != 0) 621 | { 622 | len--; 623 | dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; 624 | dicPos++; 625 | } 626 | p->dicPos = dicPos; 627 | } 628 | } 629 | 630 | 631 | #define kRange0 0xFFFFFFFF 632 | #define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)) 633 | #define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))) 634 | #if kBadRepCode != (0xC0000000 - 0x400) 635 | #error Stop_Compiling_Bad_LZMA_Check 636 | #endif 637 | 638 | static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) 639 | { 640 | do 641 | { 642 | SizeT limit2 = limit; 643 | if (p->checkDicSize == 0) 644 | { 645 | UInt32 rem = p->prop.dicSize - p->processedPos; 646 | if (limit - p->dicPos > rem) 647 | limit2 = p->dicPos + rem; 648 | 649 | if (p->processedPos == 0) 650 | if (p->code >= kBadRepCode) 651 | return SZ_ERROR_DATA; 652 | } 653 | 654 | RINOK(LZMA_DECODE_REAL(p, limit2, bufLimit)); 655 | 656 | if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) 657 | p->checkDicSize = p->prop.dicSize; 658 | 659 | LzmaDec_WriteRem(p, limit); 660 | } 661 | while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); 662 | 663 | return 0; 664 | } 665 | 666 | typedef enum 667 | { 668 | DUMMY_ERROR, /* unexpected end of input stream */ 669 | DUMMY_LIT, 670 | DUMMY_MATCH, 671 | DUMMY_REP 672 | } ELzmaDummy; 673 | 674 | static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) 675 | { 676 | UInt32 range = p->range; 677 | UInt32 code = p->code; 678 | const Byte *bufLimit = buf + inSize; 679 | const CLzmaProb *probs = GET_PROBS; 680 | unsigned state = (unsigned) p->state; 681 | ELzmaDummy res; 682 | 683 | { 684 | const CLzmaProb *prob; 685 | UInt32 bound; 686 | unsigned ttt; 687 | unsigned posState = CALC_POS_STATE(p->processedPos, (1 << p->prop.pb) - 1); 688 | 689 | prob = probs + IsMatch + COMBINED_PS_STATE; 690 | 691 | IF_BIT_0_CHECK(prob) 692 | { 693 | UPDATE_0_CHECK 694 | 695 | /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ 696 | 697 | prob = probs + Literal; 698 | if (p->checkDicSize != 0 || p->processedPos != 0) 699 | prob += ((UInt32) LZMA_LIT_SIZE * 700 | ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + 701 | (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); 702 | 703 | if (state < kNumLitStates) 704 | { 705 | unsigned symbol = 1; 706 | do 707 | { 708 | GET_BIT_CHECK(prob + symbol, symbol) 709 | } 710 | while (symbol < 0x100); 711 | } 712 | else 713 | { 714 | unsigned matchByte = p->dic[p->dicPos - p->reps[0] + 715 | (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; 716 | unsigned offs = 0x100; 717 | unsigned symbol = 1; 718 | do 719 | { 720 | unsigned bit; 721 | const CLzmaProb *probLit; 722 | matchByte += matchByte; 723 | bit = offs; 724 | offs &= matchByte; 725 | probLit = prob + (offs + bit + symbol); 726 | GET_BIT2_CHECK(probLit, symbol, offs ^= bit;,;) 727 | } 728 | while (symbol < 0x100); 729 | } 730 | res = DUMMY_LIT; 731 | } 732 | else 733 | { 734 | unsigned len; 735 | UPDATE_1_CHECK; 736 | 737 | prob = probs + IsRep + state; 738 | 739 | IF_BIT_0_CHECK(prob) 740 | { 741 | UPDATE_0_CHECK; 742 | state = 0; 743 | prob = probs + LenCoder; 744 | res = DUMMY_MATCH; 745 | } 746 | else 747 | { 748 | UPDATE_1_CHECK; 749 | res = DUMMY_REP; 750 | prob = probs + IsRepG0 + state; 751 | 752 | IF_BIT_0_CHECK(prob) 753 | { 754 | UPDATE_0_CHECK; 755 | prob = probs + IsRep0Long + COMBINED_PS_STATE; 756 | 757 | IF_BIT_0_CHECK(prob) 758 | { 759 | UPDATE_0_CHECK; 760 | NORMALIZE_CHECK; 761 | return DUMMY_REP; 762 | } 763 | else 764 | { 765 | UPDATE_1_CHECK; 766 | } 767 | } 768 | else 769 | { 770 | UPDATE_1_CHECK; 771 | prob = probs + IsRepG1 + state; 772 | 773 | IF_BIT_0_CHECK(prob) 774 | { 775 | UPDATE_0_CHECK; 776 | } 777 | else 778 | { 779 | UPDATE_1_CHECK; 780 | prob = probs + IsRepG2 + state; 781 | 782 | IF_BIT_0_CHECK(prob) 783 | { 784 | UPDATE_0_CHECK; 785 | } 786 | else 787 | { 788 | UPDATE_1_CHECK; 789 | } 790 | } 791 | } 792 | state = kNumStates; 793 | prob = probs + RepLenCoder; 794 | } 795 | { 796 | unsigned limit, offset; 797 | const CLzmaProb *probLen = prob + LenChoice; 798 | 799 | IF_BIT_0_CHECK(probLen) 800 | { 801 | UPDATE_0_CHECK; 802 | probLen = prob + LenLow + GET_LEN_STATE; 803 | offset = 0; 804 | limit = 1 << kLenNumLowBits; 805 | } 806 | else 807 | { 808 | UPDATE_1_CHECK; 809 | probLen = prob + LenChoice2; 810 | 811 | IF_BIT_0_CHECK(probLen) 812 | { 813 | UPDATE_0_CHECK; 814 | probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); 815 | offset = kLenNumLowSymbols; 816 | limit = 1 << kLenNumLowBits; 817 | } 818 | else 819 | { 820 | UPDATE_1_CHECK; 821 | probLen = prob + LenHigh; 822 | offset = kLenNumLowSymbols * 2; 823 | limit = 1 << kLenNumHighBits; 824 | } 825 | } 826 | TREE_DECODE_CHECK(probLen, limit, len); 827 | len += offset; 828 | } 829 | 830 | if (state < 4) 831 | { 832 | unsigned posSlot; 833 | prob = probs + PosSlot + 834 | ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << 835 | kNumPosSlotBits); 836 | TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); 837 | if (posSlot >= kStartPosModelIndex) 838 | { 839 | unsigned numDirectBits = ((posSlot >> 1) - 1); 840 | 841 | /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ 842 | 843 | if (posSlot < kEndPosModelIndex) 844 | { 845 | prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits); 846 | } 847 | else 848 | { 849 | numDirectBits -= kNumAlignBits; 850 | do 851 | { 852 | NORMALIZE_CHECK 853 | range >>= 1; 854 | code -= range & (((code - range) >> 31) - 1); 855 | /* if (code >= range) code -= range; */ 856 | } 857 | while (--numDirectBits); 858 | prob = probs + Align; 859 | numDirectBits = kNumAlignBits; 860 | } 861 | { 862 | unsigned i = 1; 863 | unsigned m = 1; 864 | do 865 | { 866 | REV_BIT_CHECK(prob, i, m); 867 | } 868 | while (--numDirectBits); 869 | } 870 | } 871 | } 872 | } 873 | } 874 | NORMALIZE_CHECK; 875 | return res; 876 | } 877 | 878 | void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState) 879 | { 880 | p->remainLen = kMatchSpecLenStart + 1; 881 | p->tempBufSize = 0; 882 | 883 | if (initDic) 884 | { 885 | p->processedPos = 0; 886 | p->checkDicSize = 0; 887 | p->remainLen = kMatchSpecLenStart + 2; 888 | } 889 | if (initState) 890 | p->remainLen = kMatchSpecLenStart + 2; 891 | } 892 | 893 | void LzmaDec_Init(CLzmaDec *p) 894 | { 895 | p->dicPos = 0; 896 | LzmaDec_InitDicAndState(p, True, True); 897 | } 898 | 899 | SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, 900 | ELzmaFinishMode finishMode, ELzmaStatus *status) 901 | { 902 | SizeT inSize = *srcLen; 903 | (*srcLen) = 0; 904 | 905 | *status = LZMA_STATUS_NOT_SPECIFIED; 906 | if (p->remainLen > kMatchSpecLenStart) 907 | { 908 | for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) 909 | p->tempBuf[p->tempBufSize++] = *src++; 910 | if (p->tempBufSize != 0 && p->tempBuf[0] != 0) 911 | return SZ_ERROR_DATA; 912 | if (p->tempBufSize < RC_INIT_SIZE) 913 | { 914 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; 915 | return SZ_OK; 916 | } 917 | p->code = 918 | ((UInt32) p->tempBuf[1] << 24) 919 | | ((UInt32) p->tempBuf[2] << 16) 920 | | ((UInt32) p->tempBuf[3] << 8) 921 | | ((UInt32) p->tempBuf[4]); 922 | p->range = 0xFFFFFFFF; 923 | p->tempBufSize = 0; 924 | 925 | if (p->remainLen > kMatchSpecLenStart + 1) 926 | { 927 | SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); 928 | SizeT i; 929 | CLzmaProb *probs = p->probs; 930 | for (i = 0; i < numProbs; i++) 931 | probs[i] = kBitModelTotal >> 1; 932 | p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; 933 | p->state = 0; 934 | } 935 | 936 | p->remainLen = 0; 937 | } 938 | LzmaDec_WriteRem(p, dicLimit); 939 | 940 | while (p->remainLen != kMatchSpecLenStart) 941 | { 942 | int checkEndMarkNow = 0; 943 | 944 | if (p->dicPos >= dicLimit) 945 | { 946 | if (p->remainLen == 0 && p->code == 0) 947 | { 948 | *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; 949 | return SZ_OK; 950 | } 951 | if (finishMode == LZMA_FINISH_ANY) 952 | { 953 | *status = LZMA_STATUS_NOT_FINISHED; 954 | return SZ_OK; 955 | } 956 | if (p->remainLen != 0) 957 | { 958 | *status = LZMA_STATUS_NOT_FINISHED; 959 | return SZ_ERROR_DATA; 960 | } 961 | checkEndMarkNow = 1; 962 | } 963 | 964 | if (p->tempBufSize == 0) 965 | { 966 | SizeT processed; 967 | const Byte *bufLimit; 968 | if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) 969 | { 970 | int dummyRes = LzmaDec_TryDummy(p, src, inSize); 971 | if (dummyRes == DUMMY_ERROR) 972 | { 973 | memcpy(p->tempBuf, src, inSize); 974 | p->tempBufSize = (unsigned) inSize; 975 | (*srcLen) += inSize; 976 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; 977 | return SZ_OK; 978 | } 979 | if (checkEndMarkNow && dummyRes != DUMMY_MATCH) 980 | { 981 | *status = LZMA_STATUS_NOT_FINISHED; 982 | return SZ_ERROR_DATA; 983 | } 984 | bufLimit = src; 985 | } 986 | else 987 | bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; 988 | p->buf = src; 989 | if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) 990 | return SZ_ERROR_DATA; 991 | processed = (SizeT)(p->buf - src); 992 | (*srcLen) += processed; 993 | src += processed; 994 | inSize -= processed; 995 | } 996 | else 997 | { 998 | unsigned rem = p->tempBufSize, lookAhead = 0; 999 | while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) 1000 | p->tempBuf[rem++] = src[lookAhead++]; 1001 | p->tempBufSize = rem; 1002 | if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) 1003 | { 1004 | int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, (SizeT) rem); 1005 | if (dummyRes == DUMMY_ERROR) 1006 | { 1007 | (*srcLen) += (SizeT) lookAhead; 1008 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; 1009 | return SZ_OK; 1010 | } 1011 | if (checkEndMarkNow && dummyRes != DUMMY_MATCH) 1012 | { 1013 | *status = LZMA_STATUS_NOT_FINISHED; 1014 | return SZ_ERROR_DATA; 1015 | } 1016 | } 1017 | p->buf = p->tempBuf; 1018 | if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) 1019 | return SZ_ERROR_DATA; 1020 | 1021 | { 1022 | unsigned kkk = (unsigned)(p->buf - p->tempBuf); 1023 | if (rem < kkk) 1024 | return SZ_ERROR_FAIL; /* some internal error */ 1025 | rem -= kkk; 1026 | if (lookAhead < rem) 1027 | return SZ_ERROR_FAIL; /* some internal error */ 1028 | lookAhead -= rem; 1029 | } 1030 | (*srcLen) += (SizeT) lookAhead; 1031 | src += lookAhead; 1032 | inSize -= (SizeT) lookAhead; 1033 | p->tempBufSize = 0; 1034 | } 1035 | } 1036 | 1037 | if (p->code != 0) 1038 | return SZ_ERROR_DATA; 1039 | *status = LZMA_STATUS_FINISHED_WITH_MARK; 1040 | return SZ_OK; 1041 | } 1042 | 1043 | SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) 1044 | { 1045 | SizeT outSize = *destLen; 1046 | SizeT inSize = *srcLen; 1047 | *srcLen = *destLen = 0; 1048 | for (;;) 1049 | { 1050 | SizeT inSizeCur = inSize, outSizeCur, dicPos; 1051 | ELzmaFinishMode curFinishMode; 1052 | SRes res; 1053 | 1054 | if (p->dicPos == p->dicBufSize) 1055 | p->dicPos = 0; 1056 | dicPos = p->dicPos; 1057 | 1058 | if (outSize > p->dicBufSize - dicPos) 1059 | { 1060 | outSizeCur = p->dicBufSize; 1061 | curFinishMode = LZMA_FINISH_ANY; 1062 | } 1063 | else 1064 | { 1065 | outSizeCur = dicPos + outSize; 1066 | curFinishMode = finishMode; 1067 | } 1068 | 1069 | res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); 1070 | src += inSizeCur; 1071 | inSize -= inSizeCur; 1072 | *srcLen += inSizeCur; 1073 | outSizeCur = p->dicPos - dicPos; 1074 | memcpy(dest, p->dic + dicPos, outSizeCur); 1075 | dest += outSizeCur; 1076 | outSize -= outSizeCur; 1077 | *destLen += outSizeCur; 1078 | if (res != 0) 1079 | return res; 1080 | if (outSizeCur == 0 || outSize == 0) 1081 | return SZ_OK; 1082 | } 1083 | } 1084 | 1085 | void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc) 1086 | { 1087 | ISzAlloc_Free(alloc, p->probs); 1088 | p->probs = NULL; 1089 | } 1090 | 1091 | static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc) 1092 | { 1093 | ISzAlloc_Free(alloc, p->dic); 1094 | p->dic = NULL; 1095 | } 1096 | 1097 | void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc) 1098 | { 1099 | LzmaDec_FreeProbs(p, alloc); 1100 | LzmaDec_FreeDict(p, alloc); 1101 | } 1102 | 1103 | SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) 1104 | { 1105 | UInt32 dicSize; 1106 | Byte d; 1107 | 1108 | if (size < LZMA_PROPS_SIZE) 1109 | return SZ_ERROR_UNSUPPORTED; 1110 | else 1111 | dicSize = data[1] | ((UInt32) data[2] << 8) | ((UInt32) data[3] << 16) | ((UInt32) data[4] << 24); 1112 | 1113 | if (dicSize < LZMA_DIC_MIN) 1114 | dicSize = LZMA_DIC_MIN; 1115 | p->dicSize = dicSize; 1116 | 1117 | d = data[0]; 1118 | if (d >= (9 * 5 * 5)) 1119 | return SZ_ERROR_UNSUPPORTED; 1120 | 1121 | p->lc = (Byte)(d % 9); 1122 | d /= 9; 1123 | p->pb = (Byte)(d / 5); 1124 | p->lp = (Byte)(d % 5); 1125 | 1126 | return SZ_OK; 1127 | } 1128 | 1129 | static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc) 1130 | { 1131 | UInt32 numProbs = LzmaProps_GetNumProbs(propNew); 1132 | if (!p->probs || numProbs != p->numProbs) 1133 | { 1134 | LzmaDec_FreeProbs(p, alloc); 1135 | p->probs = (CLzmaProb *) ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb)); 1136 | if (!p->probs) 1137 | return SZ_ERROR_MEM; 1138 | p->probs_1664 = p->probs + 1664; 1139 | p->numProbs = numProbs; 1140 | } 1141 | return SZ_OK; 1142 | } 1143 | 1144 | SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) 1145 | { 1146 | CLzmaProps propNew; 1147 | RINOK(LzmaProps_Decode(&propNew, props, propsSize)); 1148 | RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); 1149 | p->prop = propNew; 1150 | return SZ_OK; 1151 | } 1152 | 1153 | SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) 1154 | { 1155 | CLzmaProps propNew; 1156 | SizeT dicBufSize; 1157 | RINOK(LzmaProps_Decode(&propNew, props, propsSize)); 1158 | RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); 1159 | 1160 | { 1161 | UInt32 dictSize = propNew.dicSize; 1162 | SizeT mask = ((UInt32) 1 << 12) - 1; 1163 | if (dictSize >= ((UInt32) 1 << 30)) mask = ((UInt32) 1 << 22) - 1; 1164 | else if (dictSize >= ((UInt32) 1 << 22)) mask = ((UInt32) 1 << 20) - 1; 1165 | ; 1166 | dicBufSize = ((SizeT) dictSize + mask) & ~mask; 1167 | if (dicBufSize < dictSize) 1168 | dicBufSize = dictSize; 1169 | } 1170 | 1171 | if (!p->dic || dicBufSize != p->dicBufSize) 1172 | { 1173 | LzmaDec_FreeDict(p, alloc); 1174 | p->dic = (Byte *) ISzAlloc_Alloc(alloc, dicBufSize); 1175 | if (!p->dic) 1176 | { 1177 | LzmaDec_FreeProbs(p, alloc); 1178 | return SZ_ERROR_MEM; 1179 | } 1180 | } 1181 | p->dicBufSize = dicBufSize; 1182 | p->prop = propNew; 1183 | return SZ_OK; 1184 | } 1185 | 1186 | SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, 1187 | const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 1188 | ELzmaStatus *status, ISzAllocPtr alloc) 1189 | { 1190 | CLzmaDec p; 1191 | SRes res; 1192 | SizeT outSize = *destLen, inSize = *srcLen; 1193 | *destLen = *srcLen = 0; 1194 | *status = LZMA_STATUS_NOT_SPECIFIED; 1195 | if (inSize < RC_INIT_SIZE) 1196 | return SZ_ERROR_INPUT_EOF; 1197 | LzmaDec_Construct(&p); 1198 | RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); 1199 | p.dic = dest; 1200 | p.dicBufSize = outSize; 1201 | LzmaDec_Init(&p); 1202 | *srcLen = inSize; 1203 | res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); 1204 | *destLen = p.dicPos; 1205 | if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) 1206 | res = SZ_ERROR_INPUT_EOF; 1207 | LzmaDec_FreeProbs(&p, alloc); 1208 | return res; 1209 | } 1210 | -------------------------------------------------------------------------------- /lzma/LzmaDec.h: -------------------------------------------------------------------------------- 1 | /* LzmaDec.h -- LZMA Decoder 2 | 2018-04-21 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __LZMA_DEC_H 5 | #define __LZMA_DEC_H 6 | 7 | #include "7zTypes.h" 8 | 9 | EXTERN_C_BEGIN 10 | 11 | /* #define _LZMA_PROB32 */ 12 | /* _LZMA_PROB32 can increase the speed on some CPUs, 13 | but memory usage for CLzmaDec::probs will be doubled in that case */ 14 | 15 | typedef 16 | #ifdef _LZMA_PROB32 17 | UInt32 18 | #else 19 | UInt16 20 | #endif 21 | CLzmaProb; 22 | 23 | 24 | /* ---------- LZMA Properties ---------- */ 25 | 26 | #define LZMA_PROPS_SIZE 5 27 | 28 | typedef struct _CLzmaProps 29 | { 30 | Byte lc; 31 | Byte lp; 32 | Byte pb; 33 | Byte _pad_; 34 | UInt32 dicSize; 35 | } CLzmaProps; 36 | 37 | /* LzmaProps_Decode - decodes properties 38 | Returns: 39 | SZ_OK 40 | SZ_ERROR_UNSUPPORTED - Unsupported properties 41 | */ 42 | 43 | SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); 44 | 45 | 46 | /* ---------- LZMA Decoder state ---------- */ 47 | 48 | /* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. 49 | Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ 50 | 51 | #define LZMA_REQUIRED_INPUT_MAX 20 52 | 53 | typedef struct 54 | { 55 | /* Don't change this structure. ASM code can use it. */ 56 | CLzmaProps prop; 57 | CLzmaProb *probs; 58 | CLzmaProb *probs_1664; 59 | Byte *dic; 60 | SizeT dicBufSize; 61 | SizeT dicPos; 62 | const Byte *buf; 63 | UInt32 range; 64 | UInt32 code; 65 | UInt32 processedPos; 66 | UInt32 checkDicSize; 67 | UInt32 reps[4]; 68 | UInt32 state; 69 | UInt32 remainLen; 70 | 71 | UInt32 numProbs; 72 | unsigned tempBufSize; 73 | Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; 74 | } CLzmaDec; 75 | 76 | #define LzmaDec_Construct(p) { (p)->dic = NULL; (p)->probs = NULL; } 77 | 78 | void LzmaDec_Init(CLzmaDec *p); 79 | 80 | /* There are two types of LZMA streams: 81 | - Stream with end mark. That end mark adds about 6 bytes to compressed size. 82 | - Stream without end mark. You must know exact uncompressed size to decompress such stream. */ 83 | 84 | typedef enum 85 | { 86 | LZMA_FINISH_ANY, /* finish at any point */ 87 | LZMA_FINISH_END /* block must be finished at the end */ 88 | } ELzmaFinishMode; 89 | 90 | /* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! 91 | 92 | You must use LZMA_FINISH_END, when you know that current output buffer 93 | covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. 94 | 95 | If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, 96 | and output value of destLen will be less than output buffer size limit. 97 | You can check status result also. 98 | 99 | You can use multiple checks to test data integrity after full decompression: 100 | 1) Check Result and "status" variable. 101 | 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. 102 | 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. 103 | You must use correct finish mode in that case. */ 104 | 105 | typedef enum 106 | { 107 | LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ 108 | LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ 109 | LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ 110 | LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ 111 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ 112 | } ELzmaStatus; 113 | 114 | /* ELzmaStatus is used only as output value for function call */ 115 | 116 | 117 | /* ---------- Interfaces ---------- */ 118 | 119 | /* There are 3 levels of interfaces: 120 | 1) Dictionary Interface 121 | 2) Buffer Interface 122 | 3) One Call Interface 123 | You can select any of these interfaces, but don't mix functions from different 124 | groups for same object. */ 125 | 126 | 127 | /* There are two variants to allocate state for Dictionary Interface: 128 | 1) LzmaDec_Allocate / LzmaDec_Free 129 | 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs 130 | You can use variant 2, if you set dictionary buffer manually. 131 | For Buffer Interface you must always use variant 1. 132 | 133 | LzmaDec_Allocate* can return: 134 | SZ_OK 135 | SZ_ERROR_MEM - Memory allocation error 136 | SZ_ERROR_UNSUPPORTED - Unsupported properties 137 | */ 138 | 139 | SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); 140 | void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc); 141 | 142 | SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); 143 | void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc); 144 | 145 | /* ---------- Dictionary Interface ---------- */ 146 | 147 | /* You can use it, if you want to eliminate the overhead for data copying from 148 | dictionary to some other external buffer. 149 | You must work with CLzmaDec variables directly in this interface. 150 | 151 | STEPS: 152 | LzmaDec_Construct() 153 | LzmaDec_Allocate() 154 | for (each new stream) 155 | { 156 | LzmaDec_Init() 157 | while (it needs more decompression) 158 | { 159 | LzmaDec_DecodeToDic() 160 | use data from CLzmaDec::dic and update CLzmaDec::dicPos 161 | } 162 | } 163 | LzmaDec_Free() 164 | */ 165 | 166 | /* LzmaDec_DecodeToDic 167 | 168 | The decoding to internal dictionary buffer (CLzmaDec::dic). 169 | You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! 170 | 171 | finishMode: 172 | It has meaning only if the decoding reaches output limit (dicLimit). 173 | LZMA_FINISH_ANY - Decode just dicLimit bytes. 174 | LZMA_FINISH_END - Stream must be finished after dicLimit. 175 | 176 | Returns: 177 | SZ_OK 178 | status: 179 | LZMA_STATUS_FINISHED_WITH_MARK 180 | LZMA_STATUS_NOT_FINISHED 181 | LZMA_STATUS_NEEDS_MORE_INPUT 182 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK 183 | SZ_ERROR_DATA - Data error 184 | */ 185 | 186 | SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, 187 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); 188 | 189 | 190 | /* ---------- Buffer Interface ---------- */ 191 | 192 | /* It's zlib-like interface. 193 | See LzmaDec_DecodeToDic description for information about STEPS and return results, 194 | but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need 195 | to work with CLzmaDec variables manually. 196 | 197 | finishMode: 198 | It has meaning only if the decoding reaches output limit (*destLen). 199 | LZMA_FINISH_ANY - Decode just destLen bytes. 200 | LZMA_FINISH_END - Stream must be finished after (*destLen). 201 | */ 202 | 203 | SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, 204 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); 205 | 206 | 207 | /* ---------- One Call Interface ---------- */ 208 | 209 | /* LzmaDecode 210 | 211 | finishMode: 212 | It has meaning only if the decoding reaches output limit (*destLen). 213 | LZMA_FINISH_ANY - Decode just destLen bytes. 214 | LZMA_FINISH_END - Stream must be finished after (*destLen). 215 | 216 | Returns: 217 | SZ_OK 218 | status: 219 | LZMA_STATUS_FINISHED_WITH_MARK 220 | LZMA_STATUS_NOT_FINISHED 221 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK 222 | SZ_ERROR_DATA - Data error 223 | SZ_ERROR_MEM - Memory allocation error 224 | SZ_ERROR_UNSUPPORTED - Unsupported properties 225 | SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). 226 | */ 227 | 228 | SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, 229 | const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 230 | ELzmaStatus *status, ISzAllocPtr alloc); 231 | 232 | EXTERN_C_END 233 | 234 | #endif 235 | -------------------------------------------------------------------------------- /lzma/LzmaEnc.h: -------------------------------------------------------------------------------- 1 | /* LzmaEnc.h -- LZMA Encoder 2 | 2017-07-27 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __LZMA_ENC_H 5 | #define __LZMA_ENC_H 6 | 7 | #include "7zTypes.h" 8 | 9 | EXTERN_C_BEGIN 10 | 11 | #define LZMA_PROPS_SIZE 5 12 | 13 | typedef struct _CLzmaEncProps 14 | { 15 | int level; /* 0 <= level <= 9 */ 16 | UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version 17 | (1 << 12) <= dictSize <= (3 << 29) for 64-bit version 18 | default = (1 << 24) */ 19 | int lc; /* 0 <= lc <= 8, default = 3 */ 20 | int lp; /* 0 <= lp <= 4, default = 0 */ 21 | int pb; /* 0 <= pb <= 4, default = 2 */ 22 | int algo; /* 0 - fast, 1 - normal, default = 1 */ 23 | int fb; /* 5 <= fb <= 273, default = 32 */ 24 | int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ 25 | int numHashBytes; /* 2, 3 or 4, default = 4 */ 26 | UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ 27 | unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ 28 | int numThreads; /* 1 or 2, default = 2 */ 29 | 30 | UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1. 31 | Encoder uses this value to reduce dictionary size */ 32 | } CLzmaEncProps; 33 | 34 | void LzmaEncProps_Init(CLzmaEncProps *p); 35 | void LzmaEncProps_Normalize(CLzmaEncProps *p); 36 | UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); 37 | 38 | 39 | /* ---------- CLzmaEncHandle Interface ---------- */ 40 | 41 | /* LzmaEnc* functions can return the following exit codes: 42 | SRes: 43 | SZ_OK - OK 44 | SZ_ERROR_MEM - Memory allocation error 45 | SZ_ERROR_PARAM - Incorrect paramater in props 46 | SZ_ERROR_WRITE - ISeqOutStream write callback error 47 | SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output 48 | SZ_ERROR_PROGRESS - some break from progress callback 49 | SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) 50 | */ 51 | 52 | typedef void * CLzmaEncHandle; 53 | 54 | CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc); 55 | void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig); 56 | 57 | SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); 58 | void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize); 59 | SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); 60 | unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p); 61 | 62 | SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, 63 | ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); 64 | SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, 65 | int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); 66 | 67 | 68 | /* ---------- One Call Interface ---------- */ 69 | 70 | SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, 71 | const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, 72 | ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); 73 | 74 | EXTERN_C_END 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /lzma/Precomp.h: -------------------------------------------------------------------------------- 1 | /* Precomp.h -- StdAfx 2 | 2013-11-12 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __7Z_PRECOMP_H 5 | #define __7Z_PRECOMP_H 6 | 7 | #define _7ZIP_ST 8 | #include "Compiler.h" 9 | /* #include "7zTypes.h" */ 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /lzma/lzma_decompress.c: -------------------------------------------------------------------------------- 1 | // #include 2 | #include 3 | #include 4 | #include 5 | #include "bs_user_interface.h" 6 | #include "LzmaDec.h" 7 | #include "LzmaEnc.h" 8 | #include "7zFile.h" 9 | #include "vFile.h" 10 | #include "mylib.h" 11 | 12 | //#define LZMA_RAM_USE_DEBUG 13 | 14 | #ifdef LZMA_RAM_USE_DEBUG 15 | static int ram_used_size = 0; 16 | static int ram_used_max = 0; 17 | #endif 18 | 19 | void *lzma_alloc(ISzAllocPtr p, size_t size) 20 | { 21 | void *mp; 22 | 23 | if (size == 0) 24 | { 25 | return NULL; 26 | } 27 | 28 | mp = vmalloc(size); 29 | 30 | #ifdef LZMA_RAM_USE_DEBUG 31 | ram_used_size += _msize(mp); 32 | if (ram_used_max < ram_used_size)ram_used_max = ram_used_size; 33 | printk("ram used: now / max = %d / %d\n", ram_used_size, ram_used_max); 34 | #endif 35 | 36 | return mp; 37 | } 38 | 39 | void lzma_free(ISzAllocPtr p, void *address) 40 | { 41 | if (address != NULL) 42 | { 43 | #ifdef LZMA_RAM_USE_DEBUG 44 | ram_used_size -= _msize(address); 45 | printk("ram used: now / max = %d / %d\n", ram_used_size, ram_used_max); 46 | #endif 47 | vfree(address); 48 | } 49 | } 50 | 51 | ISzAlloc allocator = {lzma_alloc, lzma_free}; 52 | static CLzmaDec *lz_state = NULL; 53 | 54 | static int lzma_decompress_init(vFile *pf) 55 | { 56 | if (lz_state != NULL) return 0; 57 | 58 | extern ISzAlloc allocator; 59 | UInt64 unpack_size = 0; 60 | uint8_t header[LZMA_PROPS_SIZE + 8];; 61 | size_t headerSize = sizeof(header); 62 | 63 | vfread(pf, header, headerSize); 64 | // debug_array(header, headerSize); 65 | // for (char i = 0; i < 8; i++) 66 | // { 67 | // unpack_size |= (UInt64)(header[LZMA_PROPS_SIZE + i] << (i * 8)); 68 | // } 69 | /* 以下为过静态检查写法 */ 70 | unpack_size |= ((uint64_t)header[LZMA_PROPS_SIZE + 0]) << 0; 71 | unpack_size |= ((uint64_t)header[LZMA_PROPS_SIZE + 1]) << 8; 72 | unpack_size |= ((uint64_t)header[LZMA_PROPS_SIZE + 2]) << 16; 73 | unpack_size |= ((uint64_t)header[LZMA_PROPS_SIZE + 3]) << 24; 74 | unpack_size |= ((uint64_t)header[LZMA_PROPS_SIZE + 4]) << 32; 75 | unpack_size |= ((uint64_t)header[LZMA_PROPS_SIZE + 5]) << 40; 76 | unpack_size |= ((uint64_t)header[LZMA_PROPS_SIZE + 6]) << 48; 77 | unpack_size |= ((uint64_t)header[LZMA_PROPS_SIZE + 7]) << 56; 78 | // bs_printf("unpack_size:0X%08X", unpack_size); 79 | 80 | //分配解码内存 81 | lz_state = (CLzmaDec *)lzma_alloc(NULL, sizeof(CLzmaDec)); 82 | 83 | if (lz_state != NULL) 84 | { 85 | LzmaDec_Construct(lz_state); 86 | LzmaDec_Allocate(lz_state, header, LZMA_PROPS_SIZE, &allocator); 87 | LzmaDec_Init(lz_state); 88 | 89 | return 0; 90 | } 91 | else 92 | { 93 | bs_printf("lzma_alloc err"); 94 | } 95 | 96 | return -1; 97 | } 98 | 99 | int lzma_decompress_read(vFile *pf, uint8_t *buffer, int size) 100 | { 101 | /* Start to decompress file */ 102 | uint32_t position, file_size; 103 | size_t dcmprs_size = 0; 104 | uint8_t *inBuf; 105 | SizeT inProcessed; 106 | SizeT outProcessed = size; 107 | ELzmaFinishMode finishMode = LZMA_FINISH_ANY; 108 | ELzmaStatus status; 109 | SRes res; 110 | 111 | res = lzma_decompress_init(pf); 112 | if (res != 0) 113 | { 114 | bs_printf("err%d", __LINE__); 115 | } 116 | 117 | //获取当前文件读指针 118 | inBuf = vfgetpos(pf, &position); 119 | //检查文件还剩下多少字节 120 | file_size = vfgetlen(pf); 121 | // bs_printf("file_size:%d", file_size); 122 | if ((position + size) > file_size) 123 | { 124 | inProcessed = file_size - position; 125 | } 126 | else 127 | { 128 | inProcessed = size; 129 | } 130 | // bs_printf("inProcessed:%d", inProcessed); 131 | 132 | //解压数据 133 | if (inProcessed > 0 || inProcessed == 0) 134 | { 135 | res = LzmaDec_DecodeToBuf(lz_state, buffer, &outProcessed, inBuf, &inProcessed, finishMode, &status); 136 | // debug_array((uint8_t *)lz_state, 200); 137 | // debug_array(buffer, 255); 138 | // bs_printf("outProcessed: %d", outProcessed); 139 | // debug_array(inBuf, 255); 140 | // bs_printf("inProcessed: %d", inProcessed); 141 | // bs_printf("finishMode: %d", finishMode); 142 | // bs_printf("status: %d", status); 143 | // bs_printf("LzmaDec_DecodeToBuf res: %d", res); 144 | if (res) 145 | { 146 | // bs_printf("err%d,res: %d", __LINE__, res); 147 | } 148 | dcmprs_size = outProcessed; 149 | 150 | //重新设置文件读指针 151 | position += inProcessed; 152 | vfsetpos(pf, position); 153 | } 154 | // bs_printf("dcmprs_size: %d", dcmprs_size); 155 | return dcmprs_size; 156 | } 157 | 158 | void lzma_decompress_finish(void) 159 | { 160 | LzmaDec_Free(lz_state, &allocator); 161 | 162 | if (lz_state != NULL) 163 | { 164 | lzma_free(NULL, lz_state); 165 | lz_state = NULL; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /lzma/lzma_decompress.h: -------------------------------------------------------------------------------- 1 | #ifndef __LZMA_SAMPLE_H__ 2 | #define __LZMA_SAMPLE_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | #include 9 | #include "vFile.h" 10 | 11 | int lzma_decompress_read(vFile* pf, uint8_t *buffer, int size); 12 | void lzma_decompress_finish(void); 13 | 14 | #ifdef __cplusplus 15 | } 16 | #endif 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /user/bs_type.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPE_H__ 2 | #define __TYPE_H__ 3 | /********************************************************************************************************/ 4 | #include 5 | #include 6 | #include 7 | 8 | #ifndef TRUE 9 | #define TRUE 1 10 | #endif 11 | 12 | #ifndef FALSE 13 | #define FALSE 0 14 | #endif 15 | 16 | #ifndef ERROR 17 | #define ERROR 0xFF 18 | #endif 19 | 20 | // typedef unsigned char bool; 21 | // typedef unsigned char uint8_t; /* defined for unsigned 8-bits integer variable 无符号8位整型变量 */ 22 | // typedef signed char int8; /* defined for signed 8-bits integer variable 有符号8位整型变量 */ 23 | // typedef unsigned short uint16_t; /* defined for unsigned 16-bits integer variable 无符号16位整型变量 */ 24 | // typedef signed short int16; /* defined for signed 16-bits integer variable 有符号16位整型变量 */ 25 | // typedef unsigned long uint32_t; /* defined for unsigned 32-bits integer variable 无符号32位整型变量 */ 26 | // typedef signed long int32; /* defined for signed 32-bits integer variable 有符号32位整型变量 */ 27 | // typedef float fp32; /* single precision floating point variable (32bits)单精度浮点数(32位长度) */ 28 | // typedef unsigned long long uint64; /* defined for unsigned 64-bits integer variable 无符号64位整型变量 */ 29 | // typedef signed long long int64; /* defined for signed 64-bits integer variable 有符号64位整型变量 */ 30 | // typedef double fp64; /* double precision floating point variable (64bits)双精度浮点数(64位长度) */ 31 | /********************************************************************************************************/ 32 | #define BigtoLittle16(x) ((((uint16_t)(x) & 0xff00) >> 8) | (((uint16_t)(x) & 0x00ff) << 8)) 33 | #define BigtoLittle32(x) ((((uint32_t)(x) & 0xff000000) >> 24) | \ 34 | (((uint32_t)(x) & 0x00ff0000) >> 8) | \ 35 | (((uint32_t)(x) & 0x0000ff00) << 8) | \ 36 | (((uint32_t)(x) & 0x000000ff) << 24)) 37 | /********************************************************************************************************/ 38 | //定义一个联合,将一个64位数分拆成4个8位数,以便于计算 39 | //M3内核为小端方式,即低字节在低位,高字节在高位 40 | typedef union 41 | { 42 | uint64_t d64; 43 | uint8_t d8[8]; 44 | } U64_U8; 45 | //定义一个联合,将一个64位数分拆成4个8位数,以便于计算 46 | //M3内核为小端方式,即低字节在低位,高字节在高位 47 | typedef union 48 | { 49 | double f64; 50 | uint8_t d8[8]; 51 | } F64_U8; 52 | //定义一个联合,将一个32位数分拆成4个8位数,以便于计算 53 | //M3内核为小端方式,即低字节在低位,高字节在高位 54 | typedef union 55 | { 56 | uint32_t d32; 57 | uint8_t d8[4]; 58 | } U32_U8; 59 | /********************************************************************************************************/ 60 | //定义一个联合,将一个16位数分拆成2个8位数,以便于计算 61 | typedef union 62 | { 63 | uint16_t d16; 64 | uint8_t d8[2]; 65 | } U16_U8; 66 | /********************************************************************************************************/ 67 | //定义一个联合,将一个16位数分拆成2个8位数,以便于计算 68 | typedef union 69 | { 70 | int16_t d16; 71 | uint8_t d8[2]; 72 | } I16_U8; 73 | /********************************************************************************************************/ 74 | #endif 75 | -------------------------------------------------------------------------------- /user/bs_user_interface.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bs_user_func.c 3 | * @author your name (you@domain.com) 4 | * @brief 5 | * @version 0.1 6 | * @date 2022-11-09 7 | * 8 | * @copyright Copyright (c) 2022 9 | * 10 | */ 11 | #include "bs_user_interface.h" 12 | #include "bs_type.h" 13 | 14 | bs_user_interface bs_user_func; 15 | 16 | /** 17 | * @brief 用户需要注册的函数 18 | * 19 | * @param user_func 用户创建一个结构体然后将功能依次注册 20 | * @return 0成功 1失败 21 | */ 22 | int bs_user_func_register(bs_user_interface *user_func) 23 | { 24 | if (user_func == NULL || user_func->bs_flash_write == NULL 25 | || user_func->bs_malloc == NULL 26 | || user_func->bs_free == NULL 27 | ) 28 | { 29 | return 1; 30 | } 31 | bs_user_func.bs_flash_write = user_func->bs_flash_write; 32 | bs_user_func.bs_malloc = user_func->bs_malloc; 33 | bs_user_func.bs_free = user_func->bs_free; 34 | return 0; 35 | } 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /user/bs_user_interface.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bs_user_func.h 3 | * @author your name (you@domain.com) 4 | * @brief 5 | * @version 0.1 6 | * @date 2022-11-09 7 | * 8 | * @copyright Copyright (c) 2022 9 | * 10 | */ 11 | 12 | #ifndef __USER_INTERFACE_H_ 13 | #define __USER_INTERFACE_H_ 14 | 15 | #include 16 | #include 17 | #include "bs_type.h" 18 | #include "bspatch.h" 19 | #include "crc32.h" 20 | 21 | #ifdef __DEBUG 22 | #define bs_printf(...) printf("\r\n"format, ##__VA_ARGS__) 23 | #else 24 | #define bs_printf(...) 25 | #endif 26 | 27 | #define IH_NMLEN (32 - 4) /* Image Name Length */ 28 | typedef struct image_header 29 | { 30 | uint32_t ih_magic; /* Image Header Magic Number */ 31 | uint32_t ih_hcrc; /* Image Header CRC Checksum 差分包包头校验 大端 */ 32 | uint32_t ih_time; /* Image Creation Timestamp */ 33 | uint32_t ih_size; /* Image Data Size 差分包的大小 大端 */ 34 | uint32_t ih_load; /* Data Load Address 上一版本旧文件的大小 */ 35 | uint32_t ih_ep; /* Entry Point Address 要升级的新文件的大小 */ 36 | uint32_t ih_dcrc; /* Image Data CRC Checksum 新文件的CRC 大端 */ 37 | uint8_t ih_os; /* Operating System */ 38 | uint8_t ih_arch; /* CPU architecture */ 39 | uint8_t ih_type; /* Image Type */ 40 | uint8_t ih_comp; /* Compression Type */ 41 | uint8_t ih_name[IH_NMLEN]; /* Image Name */ 42 | uint32_t ih_ocrc; /* Old Image Data CRC Checksum 上一版本旧文件的CRC 大端*/ 43 | } image_header_t; 44 | 45 | /** 46 | * @brief 用户需注册的flash写入功能函数,bs会调用该函数写入用户的flash,特别注意在写入之前 47 | * 用户需要擦除,也就是该函数需自带擦除功能 48 | * @param addr bs将要写入的flash地址 49 | * @param p bs传入要写入的内容 50 | * @param len bs传入要写的长度 51 | * @return int 0代表成功,其他为错误码 52 | */ 53 | typedef int (*bs_flash_write_func)(uint32_t addr, const unsigned char *p, uint32_t len); 54 | 55 | /** 56 | * @brief 用户需注册的内存申请函数,bs会调用该函数申请内存,请注意,最大可能会申请20k左右堆空间 57 | * @param size 要申请的内存大小 58 | * @return void* 返回非NULL代表成功 59 | */ 60 | typedef void *(*bs_malloc_func)(uint32_t size); 61 | 62 | /** 63 | * @brief 用户需注册的内存释放函数,bs会调用该函数释放内存 64 | * @param ptr 要释放的内存地址 65 | */ 66 | typedef void (*bs_free_func)(void *ptr); 67 | 68 | typedef struct 69 | { 70 | bs_flash_write_func bs_flash_write; 71 | bs_malloc_func bs_malloc; 72 | bs_free_func bs_free; 73 | } bs_user_interface; 74 | extern bs_user_interface bs_user_func; 75 | 76 | 77 | 78 | /******************************************************************************/ 79 | /************************************ 用户提供 *********************************/ 80 | /** 81 | * @brief 用户需要注册的函数 82 | * 83 | * @param user_func 用户创建一个结构体然后将功能依次注册 84 | * @return 0成功 1失败 85 | */ 86 | int bs_user_func_register(bs_user_interface *user_func); 87 | 88 | /******************************************************************************/ 89 | /************************************ 用户接口 *********************************/ 90 | /** 91 | * @brief 解压并还原文件,用户使用差分升级时唯一需要关心的接口 92 | * 93 | * @param old 设备中执行区代码所在的地址,用户可指定flash执行区的地址,方便算法读出来当前 94 | * 运行中的代码,用户提供 95 | * @param oldsize 设备中执行区代码的长度,用户可在差分包bin头获取,用户提供 96 | * @param patch 设备中已经下载的差分包所在的flash地址,或者ram地址,只要能让算法读出来即可 97 | * 注意,下载的差分包自带image_header_t格式的文件头,真正的差分包需要偏 98 | * 移sizeof(image_header_t)的长度,用户提供 99 | * @param patchsize 设备中已经下载的差分包的长度,用户提供,可在差分包bin头获取 100 | * @param newfile_addr 还原后的bin写入的地址,用户提供 101 | * @return int 还原的文件大小 102 | */ 103 | extern int iap_patch(const uint8_t *old, uint32_t oldsize, const uint8_t *patch, 104 | uint32_t patchsize, uint32_t newfile_addr); 105 | 106 | /* bs所使用到的crc32校验函数,用户可酌情使用 */ 107 | extern unsigned int crc32( const unsigned char *buf, unsigned int size); 108 | 109 | #endif // !__USER_INTERFACE_H_ 110 | 111 | --------------------------------------------------------------------------------