From dedfa6eba7e460d34219477968c0019334afb23f Mon Sep 17 00:00:00 2001 From: sdierg <117286953+sdierg@users.noreply.github.com> Date: Thu, 20 Jun 2024 16:38:19 +0200 Subject: [PATCH] Add check for stored sizes in parsing (#103) * added enum constant and check for stored sizes for dims other than x,y,m. * added to lax parsing. * clean-up. * clean-up and review comments. * ouput corrected. * added unit test, output correction * updated version. * added entry for verison history. * changed test data to restore test coverage. --- CMakeLists.txt | 2 +- Src/libCZI/CziParse.cpp | 15 ++ Src/libCZI/CziParse.h | 15 +- Src/libCZI/Doc/version-history.markdown | 3 +- Src/libCZI_UnitTests/test_CZIParse.cpp | 222 +++++++++++++++++++++++- 5 files changed, 251 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a7fa6e0..d72949b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # enable new "MSVC runtime library selection" (https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html) project(libCZI - VERSION 0.58.4 + VERSION 0.59.0 HOMEPAGE_URL "https://github.com/ZEISS/libczi" DESCRIPTION "libCZI is an Open Source Cross-Platform C++ library to read and write CZI") diff --git a/Src/libCZI/CziParse.cpp b/Src/libCZI/CziParse.cpp index 2c5427a0..28fdcae5 100644 --- a/Src/libCZI/CziParse.cpp +++ b/Src/libCZI/CziParse.cpp @@ -573,6 +573,21 @@ using namespace libCZI; { libCZI::DimensionIndex dim = CCZIParse::DimensionCharToDimensionIndex(subBlkDirDV->DimensionEntries[i].Dimension, 4); entry.coordinate.Set(dim, subBlkDirDV->DimensionEntries[i].Start); + + if(options.GetPhysicalDimensionOtherThanMMustHaveSizeOne()) + { + auto physicalSize = subBlkDirDV->DimensionEntries[i].StoredSize; + if(physicalSize != 1) + { + stringstream string_stream; + string_stream + << "Physical size for dimension '" << Utils::DimensionToChar(dim) + << "' is expected to be 1, but found " << physicalSize + << " (file-offset:" << subBlkDirDV->FilePosition << ")."; + throw LibCZICZIParseException(string_stream.str().c_str(), LibCZICZIParseException::ErrorCode::NonConformingSubBlockDimensionEntry); + } + } + if (options.GetDimensionOtherThanMMustHaveSizeOne() && subBlkDirDV->DimensionEntries[i].Size != 1) { stringstream string_stream; diff --git a/Src/libCZI/CziParse.h b/Src/libCZI/CziParse.h index 918f38c9..42ddeb06 100644 --- a/Src/libCZI/CziParse.h +++ b/Src/libCZI/CziParse.h @@ -33,6 +33,7 @@ class CCZIParse { kDimensionXyMustBePresent = 0, kDimensionOtherThanMMustHaveSizeOne, + kPhysicalDimensionOtherThanMMustHaveSizeOne, kDimensionMMustHaveSizeOneExceptForPyramidSubblocks, kDimensionMMustHaveSizeOne, @@ -45,11 +46,16 @@ class CCZIParse /// \param enable True to enable, false to disable. void SetDimensionXyMustBePresent(bool enable) { return this->SetFlag(ParseFlags::kDimensionXyMustBePresent, enable); } + /// Require that for each subblock the physical size (for all dimensions other than X, Y and M) is "1". + /// + /// \param enable True to enable, false to disable. + void SetPhysicalDimensionOtherThanMMustHaveSizeOne(bool enable) { return this->SetFlag(ParseFlags::kPhysicalDimensionOtherThanMMustHaveSizeOne, enable); } + /// Require that for each subblock the size (for all dimensions other than X, Y and M) is "1". /// /// \param enable True to enable, false to disable. - void SetDimensionOtherThanMMustHaveSizeOne(bool enable) { return this->SetFlag(ParseFlags::kDimensionOtherThanMMustHaveSizeOne, enable); } + void SetDimensionOtherThanMMustHaveSizeOne(bool enable) { return this->SetFlag(ParseFlags::kDimensionOtherThanMMustHaveSizeOne, enable); } /// Require that for all subblocks that the size of dimension M is "1" except for pyramid subblocks. /// /// \param enable True to enable, false to disable. @@ -70,6 +76,11 @@ class CCZIParse /// \returns True if it is to be checked that the size of all dimensions other than X, Y and M is "1" for each subblock; false otherwise. bool GetDimensionOtherThanMMustHaveSizeOne() const { return this->GetFlag(ParseFlags::kDimensionOtherThanMMustHaveSizeOne); } + /// Gets a boolean indicating whether to check that the physical size of all dimensions other than X, Y and M is "1" for each subblock. + /// + /// \returns True if it is to be checked that the physical size of all dimensions other than X, Y and M is "1" for each subblock; false otherwise. + bool GetPhysicalDimensionOtherThanMMustHaveSizeOne() const { return this->GetFlag(ParseFlags::kPhysicalDimensionOtherThanMMustHaveSizeOne); } + /// Gets a boolean indicating whether to check that the size is "1" for dimension M for all non-pyramid-subblocks. /// This flag is more specific than the flag "DimensionMMustHaveSizeOne". /// @@ -86,6 +97,7 @@ class CCZIParse { this->SetDimensionXyMustBePresent(false); this->SetDimensionOtherThanMMustHaveSizeOne(false); + this->SetPhysicalDimensionOtherThanMMustHaveSizeOne(false); this->SetDimensionMMustHaveSizeOne(false); } @@ -93,6 +105,7 @@ class CCZIParse void SetStrictParsing() { this->SetDimensionXyMustBePresent(true); + this->SetPhysicalDimensionOtherThanMMustHaveSizeOne(true); this->SetDimensionOtherThanMMustHaveSizeOne(true); this->SetDimensionMMustHaveSizeOne(true); } diff --git a/Src/libCZI/Doc/version-history.markdown b/Src/libCZI/Doc/version-history.markdown index b6835e91..cd427b20 100644 --- a/Src/libCZI/Doc/version-history.markdown +++ b/Src/libCZI/Doc/version-history.markdown @@ -20,4 +20,5 @@ version history {#version_history} 0.58.1 | [95](https://github.com/ZEISS/libczi/pull/95) | some fixes for CziReaderWriter 0.58.2 | [96](https://github.com/ZEISS/libczi/pull/96) | small fixes for deficiencies reported by CodeQL 0.58.3 | [97](https://github.com/ZEISS/libczi/pull/97) | update zstd to [version 1.5.6](https://github.com/facebook/zstd/releases/tag/v1.5.6) - 0.58.4 | [99](https://github.com/ZEISS/libczi/pull/99) | fix a rare issue with curl_http_inputstream which would fail to read CZIs with an attachment-directory containing zero entries \ No newline at end of file + 0.58.4 | [99](https://github.com/ZEISS/libczi/pull/99) | fix a rare issue with curl_http_inputstream which would fail to read CZIs with an attachment-directory containing zero entries + 0.59.0 | [99](https://github.com/ZEISS/libczi/pull/103) | add a check for physical size for dimensions other than X,Y,M, they must not be >1, active for strict parsing. \ No newline at end of file diff --git a/Src/libCZI_UnitTests/test_CZIParse.cpp b/Src/libCZI_UnitTests/test_CZIParse.cpp index b349b173..f80c8ee1 100644 --- a/Src/libCZI_UnitTests/test_CZIParse.cpp +++ b/Src/libCZI_UnitTests/test_CZIParse.cpp @@ -11,9 +11,13 @@ using namespace std; namespace { - /// This is a CZI-document which contains a subblock with sizeT=2. + /// This is a CZI-document which contains a subblock with sizeT=2 and physicalSizeT=1. + /// PhysicalSizeT must be 1 for unit test coverage, otherwise an exception is thrown to early. extern const uint8_t czi_with_subblock_of_size_t2[2304]; + /// This is a CZI-document which contains a subblock with sizeT=1 and physicalSizeT=2. + extern const uint8_t czi_with_subblock_of_size_t1_physicalsize_t2[2304]; + /// This is a CZI-document which contains a subblock with sizeM=2. extern const uint8_t czi_with_subblock_of_size_m2[2304]; @@ -37,6 +41,22 @@ TEST(CZIParse, ParseSubblockDirectoryWithSubblockWithSizeTOf2AndExpectException) EXPECT_THROW(CCZIParse::ReadSubBlockDirectory(memory_stream.get(), file_header_segment_data.GetSubBlockDirectoryPosition(), parse_options), LibCZICZIParseException); } +TEST(CZIParse, ParseSubblockDirectoryWithSubblockWithSizeTOf1PhysicalSizeTOf2AndExpectException) +{ + const auto memory_stream = make_shared(czi_with_subblock_of_size_t1_physicalsize_t2, sizeof(czi_with_subblock_of_size_t1_physicalsize_t2)); + auto file_header_segment_data = CCZIParse::ReadFileHeaderSegmentData(memory_stream.get()); + + CCZIParse::SubblockDirectoryParseOptions parse_options; + + // if doing "lax dimension-entry-parsing", we expect no exception + parse_options.SetLaxParsing(); + EXPECT_NO_THROW(CCZIParse::ReadSubBlockDirectory(memory_stream.get(), file_header_segment_data.GetSubBlockDirectoryPosition(), parse_options)); + + // ...but, with strict parsing, we expect an exception + parse_options.SetStrictParsing(); + EXPECT_THROW(CCZIParse::ReadSubBlockDirectory(memory_stream.get(), file_header_segment_data.GetSubBlockDirectoryPosition(), parse_options), LibCZICZIParseException); +} + TEST(CZIParse, ParseSubblockDirectoryWithSubblockWithSizeMOf2AndExpectException) { const auto memory_stream = make_shared(czi_with_subblock_of_size_m2, sizeof(czi_with_subblock_of_size_m2)); @@ -141,7 +161,7 @@ namespace 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -270,7 +290,7 @@ namespace 0x01, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -666,4 +686,200 @@ namespace 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + const uint8_t czi_with_subblock_of_size_t1_physicalsize_t2[2304] = + { + 0x5A, 0x49, 0x53, 0x52, 0x41, 0x57, 0x46, 0x49, 0x4C, 0x45, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x97, 0x3C, 0xEF, 0x24, 0xA9, 0x55, 0x41, 0x88, 0xCB, 0xCB, 0xEB, + 0x19, 0xEC, 0x07, 0x79, 0x16, 0x97, 0x3C, 0xEF, 0x24, 0xA9, 0x55, 0x41, + 0x88, 0xCB, 0xCB, 0xEB, 0x19, 0xEC, 0x07, 0x79, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5A, 0x49, 0x53, 0x52, 0x41, 0x57, 0x53, 0x55, + 0x42, 0x42, 0x4C, 0x4F, 0x43, 0x4B, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x56, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5A, 0x49, 0x53, 0x52, 0x41, 0x57, 0x4D, 0x45, 0x54, 0x41, 0x44, 0x41, + 0x54, 0x41, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x31, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3C, 0x49, 0x6D, 0x61, 0x67, 0x65, 0x44, 0x6F, 0x63, 0x75, 0x6D, 0x65, + 0x6E, 0x74, 0x3E, 0x0A, 0x20, 0x20, 0x3C, 0x4D, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x49, 0x6E, + 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x3E, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x49, 0x6D, 0x61, 0x67, 0x65, 0x3E, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x53, 0x69, + 0x7A, 0x65, 0x58, 0x3E, 0x31, 0x3C, 0x2F, 0x53, 0x69, 0x7A, 0x65, 0x58, + 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x53, + 0x69, 0x7A, 0x65, 0x59, 0x3E, 0x31, 0x3C, 0x2F, 0x53, 0x69, 0x7A, 0x65, + 0x59, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, + 0x53, 0x69, 0x7A, 0x65, 0x43, 0x3E, 0x31, 0x3C, 0x2F, 0x53, 0x69, 0x7A, + 0x65, 0x43, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3C, 0x53, 0x69, 0x7A, 0x65, 0x54, 0x3E, 0x31, 0x3C, 0x2F, 0x53, 0x69, + 0x7A, 0x65, 0x54, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3C, 0x53, 0x69, 0x7A, 0x65, 0x4D, 0x3E, 0x31, 0x3C, 0x2F, 0x53, + 0x69, 0x7A, 0x65, 0x4D, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3C, 0x44, 0x69, 0x6D, 0x65, 0x6E, 0x73, 0x69, 0x6F, 0x6E, + 0x73, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3C, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x73, 0x3E, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3C, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x20, 0x49, 0x64, 0x3D, + 0x22, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x3A, 0x30, 0x22, 0x20, + 0x4E, 0x61, 0x6D, 0x65, 0x3D, 0x22, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, + 0x6C, 0x20, 0x23, 0x30, 0x22, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x50, 0x69, + 0x78, 0x65, 0x6C, 0x54, 0x79, 0x70, 0x65, 0x3E, 0x47, 0x72, 0x61, 0x79, + 0x38, 0x3C, 0x2F, 0x50, 0x69, 0x78, 0x65, 0x6C, 0x54, 0x79, 0x70, 0x65, + 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3C, 0x2F, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x3E, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, + 0x2F, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x73, 0x3E, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x44, 0x69, 0x6D, + 0x65, 0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x3E, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x50, 0x69, 0x78, 0x65, 0x6C, 0x54, + 0x79, 0x70, 0x65, 0x3E, 0x47, 0x72, 0x61, 0x79, 0x38, 0x3C, 0x2F, 0x50, + 0x69, 0x78, 0x65, 0x6C, 0x54, 0x79, 0x70, 0x65, 0x3E, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x49, 0x6D, 0x61, 0x67, 0x65, 0x3E, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x44, 0x6F, 0x63, 0x75, + 0x6D, 0x65, 0x6E, 0x74, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3C, 0x4E, 0x61, 0x6D, 0x65, 0x3E, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x3C, 0x2F, 0x4E, 0x61, 0x6D, 0x65, 0x3E, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x54, 0x69, 0x74, 0x6C, 0x65, + 0x3E, 0x43, 0x5A, 0x49, 0x43, 0x6D, 0x64, 0x20, 0x67, 0x65, 0x6E, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x64, 0x3C, 0x2F, 0x54, 0x69, 0x74, 0x6C, 0x65, + 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x43, + 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x3E, 0x42, 0x6F, 0x75, 0x6E, 0x64, + 0x73, 0x3A, 0x20, 0x20, 0x20, 0x20, 0x43, 0x30, 0x3A, 0x31, 0x54, 0x30, + 0x3A, 0x31, 0x3B, 0x20, 0x54, 0x69, 0x6C, 0x65, 0x2D, 0x73, 0x69, 0x7A, + 0x65, 0x3A, 0x20, 0x31, 0x20, 0x78, 0x20, 0x31, 0x3B, 0x20, 0x4D, 0x6F, + 0x73, 0x61, 0x69, 0x63, 0x3A, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x72, + 0x6F, 0x77, 0x20, 0x62, 0x79, 0x20, 0x31, 0x20, 0x63, 0x6F, 0x6C, 0x75, + 0x6D, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x30, 0x25, 0x20, 0x6F, + 0x76, 0x65, 0x72, 0x6C, 0x61, 0x70, 0x3C, 0x2F, 0x43, 0x6F, 0x6D, 0x6D, + 0x65, 0x6E, 0x74, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, + 0x2F, 0x44, 0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x3E, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x41, 0x70, 0x70, 0x6C, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x3C, 0x4E, 0x61, 0x6D, 0x65, 0x3E, 0x6C, 0x69, 0x62, + 0x43, 0x5A, 0x49, 0x72, 0x77, 0x2D, 0x54, 0x65, 0x73, 0x74, 0x3C, 0x2F, + 0x4E, 0x61, 0x6D, 0x65, 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x3C, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3E, 0x30, + 0x2E, 0x30, 0x31, 0x3C, 0x2F, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, + 0x3E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x41, 0x70, + 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x3E, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x3E, 0x0A, 0x20, 0x20, 0x3C, 0x2F, 0x4D, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3E, 0x0A, 0x3C, 0x2F, 0x49, 0x6D, + 0x61, 0x67, 0x65, 0x44, 0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x3E, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5A, 0x49, 0x53, 0x52, 0x41, 0x57, 0x44, 0x49, + 0x52, 0x45, 0x43, 0x54, 0x4F, 0x52, 0x59, 0x00, 0x20, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x56, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; }