• Home
  • Annotate
  • current directory
Name Date Size #Lines LOC

..18-Apr-2025-

inc/18-Apr-2025-

src/18-Apr-2025-

LICENSE A D18-Apr-20251.7 KiB3726

README.md A D18-Apr-202524.5 KiB582458

sub.mk A D18-Apr-2025399 1411

README.md

1![QCBOR Logo](https://github.com/laurencelundblade/qdv/blob/master/logo.png?raw=true)
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