1 2 3**QCBOR** is a powerful, commercial-quality CBOR encoder-decoder that 4implements these RFCs: 5 6* [RFC8949](https://tools.ietf.org/html/rfc8949) The CBOR Standard. (Nearly everything 7except sorting of encoded maps) 8* [RFC7049](https://tools.ietf.org/html/rfc7049) The previous CBOR standard. 9Replaced by RFC 8949. 10* [RFC8742](https://tools.ietf.org/html/rfc8742) CBOR Sequences 11* [RFC8943](https://tools.ietf.org/html/rfc8943) CBOR Dates 12 13## QCBOR Characteristics 14 15**Implemented in C with minimal dependency** – Dependent only 16 on C99, <stdint.h>, <stddef.h>, <stdbool.h> and <string.h> making 17 it highly portable. <math.h> and <fenv.h> are used too, but their 18 use can disabled. No #ifdefs or compiler options need to be set for 19 QCBOR to run correctly. 20 21**Focused on C / native data representation** – Careful conversion of 22 CBOR data types in to C data types, handling over and 23 underflow, strict typing and such so the caller doesn't have to 24 worry so much about this and so code using QCBOR passes static 25 analyzers easier. Simpler code because there is no support for 26 encoding/decoding to/from JSON, pretty printing, diagnostic 27 notation... Only encoding from native C representations and decoding 28 to native C representations is supported. 29 30**Small simple memory model** – Malloc is not needed. The encode 31 context is 176 bytes, decode context is 312 bytes and the 32 description of decoded data item is 56 bytes. Stack use is light and 33 there is no recursion. The caller supplies the memory to hold the 34 encoded CBOR and encode/decode contexts so caller has full control 35 of memory usage making it good for embedded implementations that 36 have to run in small fixed memory. 37 38**Easy decoding of maps** – The "spiffy decode" functions allow 39 fetching map items directly by label. Detection of duplicate map 40 items is automatically performed. This makes decoding of complex 41 protocols much simpler, say when compared to TinyCBOR. 42 43**Supports most of RFC 8949** – With some size limits, all data types 44 and formats in the specification are supported. Map sorting is main 45 CBOR feature that is not supported. The same decoding API supports 46 both definite and indefinite-length map and array decoding. Decoding 47 indefinite length strings is supported but requires a string 48 allocator be set up. Encoding of indefinite length strings is 49 planned, but not yet supported. 50 51**Extensible and general** – Provides a way to handle data types that 52 are not directly supported. 53 54**Secure coding style** – Uses a construct called UsefulBuf as a 55 discipline for very safe coding and handling of binary data. 56 57**Small code size** – In the smallest configuration the object 58 code is less than 4KB on 64-bit x86 CPUs. The design is such that 59 object code for QCBOR APIs not used is not referenced. 60 61**Clear documented public interface** – The public interface is 62 separated from the implementation. It can be put to use without 63 reading the source. 64 65**Comprehensive test suite** – Easy to verify on a new platform or OS 66 with the test suite. The test suite dependencies are minimal and the 67 same as the library's. 68 69## Spiffy Decode 70 71These are functions to decode particular data types. They are an 72alternative to and built on top of QCBORDecode_GetNext(). They do type 73checking and in some cases sophisticated type conversion. 74 75Spiffy decode supports easier map and array decoding. A map can be 76descended into with QCBORDecode_EnterMap(). When a map has been 77entered, members can be retrieved by label. Detection of duplicate 78map labels, an error, is automatically performed. 79 80An internal error state is maintained. This simplifies the decode 81implementation as an error check is only needed at the end of the 82decode, rather than on every function. 83 84An outcome is that decoding implementations are simple and involve 85many fewer lines of code. They also tend to parallel the encoding 86implementations as seen in the following example. 87 88 /* Encode */ 89 QCBOREncode_Init(&EncodeCtx, Buffer); 90 QCBOREncode_OpenMap(&EncodeCtx); 91 QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pE->Manufacturer); 92 QCBOREncode_AddInt64ToMap(&EncodeCtx, "Displacement", pE->uDisplacement); 93 QCBOREncode_AddInt64ToMap(&EncodeCtx, "Horsepower", pE->uHorsePower); 94 QCBOREncode_CloseMap(&EncodeCtx); 95 uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedEngine); 96 97 /* Decode */ 98 QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL); 99 QCBORDecode_EnterMap(&DecodeCtx); 100 QCBORDecode_GetTextStringInMapSZ(&DecodeCtx, "Manufacturer", &(pE->Manufacturer)); 101 QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Displacement", &(pE->uDisplacement)); 102 QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Horsepower", &(pE->uHorsePower)); 103 QCBORDecode_ExitMap(&DecodeCtx); 104 uErr = QCBORDecode_Finish(&DecodeCtx); 105 106The spiffy decode functions will handle definite and indefinite length 107maps and arrays without the caller having to do anything. This 108includes mixed definite and indefinte maps and arrays. (Some work 109remains to support map searching with indefinite length strings.) 110 111## Comparison to TinyCBOR 112 113TinyCBOR is a popular widely used implementation. Like QCBOR, 114it is a solid, well-maintained commercial quality implementation. This 115section is for folks trying to understand the difference in 116the approach between QCBOR and TinyCBOR. 117 118TinyCBOR's API is more minimalist and closer to the CBOR 119encoding mechanics than QCBOR's. QCBOR's API is at a somewhat higher 120level of abstraction. 121 122QCBOR really does implement just about everything described in 123RFC 8949. The main part missing is sorting of maps when encoding. 124TinyCBOR implements a smaller part of the standard. 125 126No detailed code size comparison has been made, but in a spot check 127that encodes and decodes a single integer shows QCBOR about 25% 128larger. QCBOR encoding is actually smaller, but QCBOR decoding is 129larger. This includes the code to call the library, which is about the 130same for both libraries, and the code linked from the libraries. QCBOR 131is a bit more powerful, so you get value for the extra code brought 132in, especially when decoding more complex protocols. 133 134QCBOR tracks encoding and decoding errors internally so the caller 135doesn't have to check the return code of every call to an encode or 136decode function. In many cases the error check is only needed as the 137last step or an encode or decode. TinyCBOR requires an error check on 138each call. 139 140QCBOR provides a substantial feature that allows searching for data 141items in a map by label. It works for integer and text string labels 142(and at some point byte-string labels). This includes detection of 143items with duplicate labels. This makes the code for decoding CBOR 144simpler, similar to the encoding code and easier to read. TinyCBOR 145supports search by string, but no integer, nor duplicate detection. 146 147QCBOR provides explicit support many of the registered CBOR tags. For 148example, QCBOR supports big numbers and decimal fractions including 149their conversion to floats, uint64_t and such. 150 151Generally, QCBOR supports safe conversion of most CBOR number formats 152into number formats supported in C. For example, a data item can be 153fetched and converted to a C uint64_t whether the input CBOR is an 154unsigned 64-bit integer, signed 64-bit integer, floating-point number, 155big number, decimal fraction or a big float. The conversion is 156performed with full proper error detection of overflow and underflow. 157 158QCBOR has a special feature for decoding byte-string wrapped CBOR. It 159treats this similar to entering an array with one item. This is 160particularly use for CBOR protocols like COSE that make use of 161byte-string wrapping. The implementation of these protocols is 162simpler and uses less memory. 163 164QCBOR's test suite is written in the same portable C that QCBOR is 165where TinyCBOR requires Qt for its test. QCBOR's test suite is 166designed to be able to run on small embedded devices the same as 167QCBOR. 168 169## Code Status 170 171The official current release is version 1.4.1 Changes over the last few 172years have been only minor bug fixes, minor feature additions and 173documentation improvements. QCBOR 1.x is highly stable. 174 175Work on some larger feature additions is ongoing in "dev" branch. 176This includes more explicit support for preferred serialization and 177CDE (CBOR Deterministic Encoding). It will eventually be release as 178QCBOR 2.x. 179 180QCBOR was originally developed by Qualcomm. It was [open sourced 181through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a 182permissive Linux license, September 2018 (thanks Qualcomm!). 183 184## Building 185 186There is a simple makefile for the UNIX style command line binary that 187compiles everything to run the tests. CMake is also available, please read 188the "Building with CMake" section for more information. 189 190These eleven files, the contents of the src and inc directories, make 191up the entire implementation. 192 193* inc 194 * UsefulBuf.h 195 * qcbor_private.h 196 * qcbor_common.h 197 * qcbor_encode.h 198 * qcbor_decode.h 199 * qcbor_spiffy_decode.h 200* src 201 * UsefulBuf.c 202 * qcbor_encode.c 203 * qcbor_decode.c 204 * ieee754.h 205 * ieee754.c 206 207For most use cases you should just be able to add them to your 208project. Hopefully the easy portability of this implementation makes 209this work straight away, whatever your development environment is. 210 211The test directory includes the tests that are nearly as portable as 212the main implementation. If your development environment doesn't 213support UNIX style command line and make, you should be able to make a 214simple project and add the test files to it. Then just call 215RunTests() to invoke them all. 216 217While this code will run fine without configuration, there are several 218C pre processor macros that can be #defined in order to: 219 220 * use a more efficient implementation 221 * to reduce code size 222 * to improve performance (a little) 223 * remove features to reduce code size 224 225See the comment sections on "Configuration" in inc/UsefulBuf.h and 226the pre processor defines that start with QCBOR_DISABLE_XXX. 227 228### Building with CMake 229 230CMake can also be used to build QCBOR and the test application. Having the root 231`CMakeLists.txt` file, QCBOR can be easily integrated with your project's 232existing CMake environment. The result of the build process is a static library, 233to build a shared library instead you must add the 234`-DBUILD_SHARED_LIBS=ON` option at the CMake configuration step. 235The tests can be built into a simple command line application to run them as it 236was mentioned before; or it can be built as a library to be integrated with your 237development environment. 238The `BUILD_QCBOR_TEST` CMake option can be used for building the tests, it can 239have three values: `APP`, `LIB` or `OFF` (default, test are not included in the 240build). 241 242Building the QCBOR library: 243 244```bash 245cd <QCBOR_base_folder> 246# Configuring the project and generating a native build system 247cmake -S . -B <build_folder> 248# Building the project 249cmake --build <build_folder> 250``` 251 252Building and running the QCBOR test app: 253```bash 254cd <QCBOR_base_folder> 255# Configuring the project and generating a native build system 256cmake -S . -B <build_folder> -DBUILD_QCBOR_TEST=APP 257# Building the project 258cmake --build <build_folder> 259# Running the test app 260.<build_folder>/test/qcbortest 261``` 262 263To enable all the compiler warnings that are used in the QCBOR release process 264you can use the `BUILD_QCBOR_WARN` option at the CMake configuration step: 265```bash 266cmake -S . -B <build_folder> -DBUILD_QCBOR_WARN=ON 267``` 268 269### Floating Point Support & Configuration 270 271By default, all QCBOR floating-point features are enabled: 272 273* Encoding and decoding of basic float types, single and double-precision 274* Encoding and decoding of half-precision with conversion to/from single 275 and double-precision 276* Preferred serialization of floating-point 277* Floating point dates 278* Methods that can convert big numbers, decimal fractions and other numbers 279 to/from floating-point 280 281If full floating-point is not needed, the following #defines can be 282used to reduce object code size and dependency. 283 284See discussion in qcbor_encode.h for other details. 285 286#### #define QCBOR_DISABLE_FLOAT_HW_USE 287 288This removes dependency on: 289 290* Floating-point hardware and floating-point instructions 291* `<math.h>` and `<fenv.h>` 292* The math library (libm, -lm) 293 294For most limited environments, this removes enough floating-point 295dependencies to be able to compile and run QCBOR. 296 297Note that this does not remove use of the types double and float from 298QCBOR, but it limits QCBOR's use of them to converting the encoded 299byte stream to them and copying them. Converting and copying them 300usually don't require any hardware, libraries or includes. The C 301compiler takes care of it on its own. 302 303QCBOR uses its own implementation of half-precision float-pointing 304that doesn't depend on math libraries. It uses masks and shifts 305instead. Thus, even with this define, half-precision encoding and 306decoding works. 307 308When this is defined, the QCBOR functionality lost is minimal and only 309for decoding: 310 311* Decoding floating-point format dates are not handled 312* There is no conversion between floats and integers when decoding. For 313 example, QCBORDecode_GetUInt64ConvertAll() will be unable to convert 314 to and from float-point. 315* Floats will be unconverted to double when decoding. 316 317No interfaces are disabled or removed with this define. If input that 318requires floating-point conversion or functions are called that 319request floating-point conversion, an error code like 320`QCBOR_ERR_HW_FLOAT_DISABLED` will be returned. 321 322This saves only a small amount of object code. The primary purpose for 323defining this is to remove dependency on floating point hardware and 324libraries. 325 326#### #define QCBOR_DISABLE_PREFERRED_FLOAT 327 328This eliminates support for half-precision 329and CBOR preferred serialization by disabling 330QCBOR's shift and mask based implementation of 331half-precision floating-point. 332 333With this defined, single and double-precision floating-point 334numbers can still be encoded and decoded. Conversion 335of floating-point to and from integers, big numbers and 336such is also supported. Floating-point dates are still 337supported. 338 339The primary reason to define this is to save object code. 340Roughly 900 bytes are saved, though about half of this 341can be saved just by not calling any functions that 342encode floating-point numbers. 343 344#### #define USEFULBUF_DISABLE_ALL_FLOAT 345 346This eliminates floating point support completely (along with related function 347headers). This is useful if the compiler options deny the usage of floating 348point operations completely, and the usage soft floating point ABI is not 349possible. 350 351#### Compiler options 352 353Compilers support a number of options that control 354which float-point related code is generated. For example, 355it is usually possible to give options to the compiler to avoid all 356floating-point hardware and instructions, to use software 357and replacement libraries instead. These are usually 358bigger and slower, but these options may still be useful 359in getting QCBOR to run in some environments in 360combination with `QCBOR_DISABLE_FLOAT_HW_USE`. 361In particular, `-mfloat-abi=soft`, disables use of 362 hardware instructions for the float and double 363 types in C for some architectures. 364 365#### CMake options 366 367If you are using CMake, it can also be used to configure the floating-point 368support. These options can be enabled by adding them to the CMake configuration 369step and setting their value to 'ON' (True). The following table shows the 370available options and the associated #defines. 371 372 | CMake option | #define | 373 |-----------------------------------|-------------------------------| 374 | QCBOR_OPT_DISABLE_FLOAT_HW_USE | QCBOR_DISABLE_FLOAT_HW_USE | 375 | QCBOR_OPT_DISABLE_FLOAT_PREFERRED | QCBOR_DISABLE_PREFERRED_FLOAT | 376 | QCBOR_OPT_DISABLE_FLOAT_ALL | USEFULBUF_DISABLE_ALL_FLOAT | 377 378## Code Size 379 380These are approximate sizes on a 64-bit x86 CPU with the -Os optimization. 381All QCBOR_DISABLE_XXX are set and compiler stack frame checking is disabled 382for smallest but not for largest. Smallest is the library functions for a 383protocol with strings, integers, arrays, maps and Booleans, but not floats 384and standard tag types. 385 386 | | smallest | largest | 387 |---------------|----------|---------| 388 | encode only | 850 | 2200 | 389 | decode only | 1550 | 13300 | 390 | combined | 2500 | 15500 | 391 392 From the table above, one can see that the amount of code pulled in 393 from the QCBOR library varies a lot, ranging from 1KB to 15KB. The 394 main factor is the number of QCBOR functions called and 395 which ones they are. QCBOR minimizes internal 396 interdependency so only code necessary for the called functions is 397 brought in. 398 399 Encoding is simpler and smaller. An encode-only implementation may 400 bring in only 1KB of code. 401 402 Encoding of floating-point brings in a little more code as does 403 encoding of tagged types and encoding of bstr wrapping. 404 405 Basic decoding using QCBORDecode_GetNext() brings in 3KB. 406 407 Use of the supplied MemPool by calling QCBORDecode_SetMemPool() to 408 setup to decode indefinite-length strings adds 0.5KB. 409 410 Basic use of spiffy decode to brings in about 3KB. Using more spiffy 411 decode functions, such as those for tagged types bstr wrapping brings 412 in more code. 413 414 Finally, use of all of the integer conversion functions will bring in 415 about 5KB, though you can use the simpler ones like 416 QCBORDecode_GetInt64() without bringing in very much code. 417 418 In addition to using fewer QCBOR functions, the following are some 419 ways to make the code smaller. 420 421 The gcc compiler output is usually smaller than llvm because stack 422 guards are off by default (be sure you actually have gcc and not llvm 423 installed to be invoked by the gcc command). You can also turn off 424 stack gaurds with llvm. It is safe to turn off stack gaurds with this 425 code because Usefulbuf provides similar defenses and this code was 426 carefully written to be defensive. 427 428 If QCBOR is installed as a shared library, then of course only one 429 copy of the code is in memory no matter how many applications use it. 430 431### Disabling Features 432 433Here's the list of all features that can be disabled to save object 434code. The amount saved is an approximation. 435 436 | #define | Saves | 437 | ----------------------------------------| ------| 438 | QCBOR_DISABLE_ENCODE_USAGE_GUARDS | 150 | 439 | QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS | 400 | 440 | QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS | 200 | 441 | QCBOR_DISABLE_UNCOMMON_TAGS | 100 | 442 | QCBOR_DISABLE_EXP_AND_MANTISSA | 400 | 443 | QCBOR_DISABLE_PREFERRED_FLOAT | 900 | 444 | QCBOR_DISABLE_FLOAT_HW_USE | 50 | 445 | QCBOR_DISABLE_TAGS | 400 | 446 | QCBOR_DISABLE_NON_INTEGER_LABELS | 140 | 447 | USEFULBUF_DISABLE_ALL_FLOAT | 950 | 448 449QCBOR_DISABLE_ENCODE_USAGE_GUARDS affects encoding only. It doesn't 450disable any encoding features, just some error checking. Disable it 451when you are confident that an encoding implementation is complete and 452correct. 453 454Indefinite lengths are a feature of CBOR that makes encoding simpler 455and the decoding more complex. They allow the encoder to not have to 456know the length of a string, map or array when they start encoding 457it. Their main use is when encoding has to be done on a very 458constrained device. Conversely when decoding on a very constrained 459device, it is good to prohibit use of indefinite lengths so the 460decoder can be smaller. 461 462The QCBOR decode API processes both definite and indefinite lengths 463with the same API, except to decode indefinite-length strings a 464storage allocator must be configured. 465 466To reduce the size of the decoder define 467QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS particularly if you are not 468configuring a storage allocator. 469 470Further reduction can be by defining 471QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS which will result in an error 472when an indefinite-length map or array arrives for decoding. 473 474QCBOR_DISABLE_UNCOMMON_TAGS disables the decoding of explicit tags for 475base 64, regex, UUID and MIME data. This just disables the automatic 476recognition of these from a major type 6 tag. 477 478QCBOR_DISABLE_EXP_AND_MANTISSA disables the decoding of decimal 479fractions and big floats. 480 481QCBOR_DISABLE_TAGS disables all decoding of CBOR tags. If the input has 482a single tag, the error is unrecoverable so it is suitable only for protocols that 483have no tags. "Borrowed" tag content formats (e.g. an epoch-based date 484without the tag number), can still be processed. 485 486QCBOR_DISABLE_NON_INTEGER_LABELS causes any label that doesn't 487fit in an int64_t to result in a QCBOR_ERR_MAP_LABEL_TYPE error. 488This also disables QCBOR_DECODE_MODE_MAP_AS_ARRAY and 489QCBOR_DECODE_MODE_MAP_STRINGS_ONLY. It is fairly common for CBOR-based 490protocols to use only small integers as labels. 491 492See the discussion above on floating-point. 493 494 ### Size of spiffy decode 495 496 When creating a decode implementation, there is a choice of whether 497 or not to use spiffy decode features or to just use 498 QCBORDecode_GetNext(). 499 500 The implementation using spiffy decode will be simpler resulting in 501 the calling code being smaller, but the amount of code brought in 502 from the QCBOR library will be larger. Basic use of spiffy decode 503 brings in about 2KB of object code. If object code size is not a 504 concern, then it is probably better to use spiffy decode because it 505 is less work, there is less complexity and less testing to worry 506 about. 507 508 If code size is a concern, then use of QCBORDecode_GetNext() will 509 probably result in smaller overall code size for simpler CBOR 510 protocols. However, if the CBOR protocol is complex then use of 511 spiffy decode may reduce overall code size. An example of a complex 512 protocol is one that involves decoding a lot of maps or maps that 513 have many data items in them. The overall code may be smaller 514 because the general purpose spiffy decode map processor is the one 515 used for all the maps. 516 517 518## Other Software Using QCBOR 519 520* [t_cose](https://github.com/laurencelundblade/t_cose) implements enough of 521[COSE, RFC 8152](https://tools.ietf.org/html/rfc8152) to support 522[CBOR Web Token (CWT)](https://tools.ietf.org/html/rfc8392) and 523[Entity Attestation Token (EAT)](https://tools.ietf.org/html/draft-ietf-rats-eat-06). 524Specifically it supports signing and verification of the COSE_Sign1 message. 525 526* [ctoken](https://github.com/laurencelundblade/ctoken) is an implementation of 527EAT and CWT. 528 529## Credits 530* Ganesh Kanike for porting to QSEE 531* Mark Bapst for sponsorship and release as open source by Qualcomm 532* Sachin Sharma for release through CAF 533* Tamas Ban for porting to TF-M and 32-bit ARM 534* Michael Eckel for Makefile improvements 535* Jan Jongboom for indefinite length encoding 536* Peter Uiterwijk for error strings and other 537* Michael Richarson for CI set up and fixing some compiler warnings 538* Máté Tóth-Pál for float-point disabling and other 539* Dave Thaler for portability to Windows 540 541## Copyright and License 542 543QCBOR is available under what is essentially the 3-Clause BSD License. 544 545Files created inside Qualcomm and open-sourced through CAF (The Code 546Aurora Forum) have a slightly modified 3-Clause BSD License. The 547modification additionally disclaims NON-INFRINGEMENT. 548 549Files created after release to CAF use the standard 3-Clause BSD 550License with no modification. These files have the SPDX license 551identifier, "SPDX-License-Identifier: BSD-3-Clause" in them. 552 553### BSD-3-Clause license 554 555* Redistributions of source code must retain the above copyright 556notice, this list of conditions and the following disclaimer. 557 558* Redistributions in binary form must reproduce the above copyright 559notice, this list of conditions and the following disclaimer in the 560documentation and/or other materials provided with the distribution. 561 562* Neither the name of the copyright holder nor the names of its 563contributors may be used to endorse or promote products derived from 564this software without specific prior written permission. 565 566THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 567"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 568LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 569A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 570HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 571SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 572LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 573DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 574THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 575(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 576OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 577 578### Copyright for this README 579 580Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. 581Copyright (c) 2021-2023, Arm Limited. All rights reserved. 582