Merge pull request #24177 from chennes/migrateLibE57ToSubtree
Migrate libE57Format to subtree
This commit is contained in:
66
src/3rdParty/libE57Format/.clang-format
vendored
66
src/3rdParty/libE57Format/.clang-format
vendored
@@ -7,7 +7,7 @@ AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
@@ -24,19 +24,20 @@ AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
@@ -48,28 +49,32 @@ BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: '@copydetails '
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 3
|
||||
ContinuationIndentWidth: 3
|
||||
Cpp11BracedListStyle: false
|
||||
DeriveLineEnding: false
|
||||
DerivePointerAlignment: false
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
FixNamespaceComments: false
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 3
|
||||
IndentWidth: 3
|
||||
IndentWrappedFunctionNames: true
|
||||
InsertBraces: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: 1
|
||||
@@ -83,13 +88,14 @@ PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
@@ -97,12 +103,12 @@ SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: true
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 3
|
||||
UseTab: Never
|
||||
...
|
||||
Standard: c++14
|
||||
TabWidth: 3
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
|
||||
@@ -4,67 +4,151 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.config.name }} (${{ matrix.build_type }})
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: ["Debug", "Release"]
|
||||
config:
|
||||
- {
|
||||
name: "macOS Clang",
|
||||
os: macos-latest,
|
||||
}
|
||||
- {
|
||||
name: "Ubuntu GCC",
|
||||
os: ubuntu-latest,
|
||||
}
|
||||
- {
|
||||
name: "Windows MSVC",
|
||||
os: windows-latest,
|
||||
}
|
||||
include:
|
||||
- name: 🍏 macOS (Clang - Debug)
|
||||
os: macos-latest
|
||||
platform: macos
|
||||
build_type: Debug
|
||||
build_shared: OFF
|
||||
build_test: ON
|
||||
validation_level: 2
|
||||
- name: 🍏 macOS (Clang, no validation - Release)
|
||||
os: macos-latest
|
||||
platform: macos
|
||||
build_type: Release
|
||||
build_shared: OFF
|
||||
build_test: ON
|
||||
validation_level: 0 # build one with no validation
|
||||
- name: 🍏 macOS (Clang, Shared - Release)
|
||||
os: macos-latest
|
||||
platform: macos
|
||||
build_type: Release
|
||||
build_shared: ON
|
||||
build_test: ON
|
||||
validation_level: 2
|
||||
|
||||
- name: 🐧 Linux (GCC - Debug)
|
||||
os: ubuntu-latest
|
||||
platform: linux
|
||||
build_type: Debug
|
||||
build_shared: OFF
|
||||
build_test: ON
|
||||
validation_level: 2
|
||||
- name: 🐧 Linux (GCC, extra validation - Release)
|
||||
os: ubuntu-latest
|
||||
platform: linux
|
||||
build_type: Release
|
||||
build_shared: OFF
|
||||
build_test: ON
|
||||
validation_level: 1 # build one with basic validation
|
||||
- name: 🐧 Linux (GCC, Shared - Release)
|
||||
os: ubuntu-latest
|
||||
platform: linux
|
||||
build_type: Release
|
||||
build_shared: ON
|
||||
build_test: ON
|
||||
validation_level: 2
|
||||
|
||||
- name: 🪟 Windows (MSVC - Debug)
|
||||
os: windows-latest
|
||||
platform: windows
|
||||
arch: x86_64
|
||||
build_type: Debug
|
||||
build_debug: ON
|
||||
build_shared: OFF
|
||||
build_test: ON
|
||||
validation_level: 2
|
||||
- name: 🪟 Windows (MSVC [32-bit] - Debug)
|
||||
os: windows-latest
|
||||
platform: windows
|
||||
arch: x86
|
||||
build_type: Debug
|
||||
build_debug: ON
|
||||
build_shared: OFF
|
||||
build_test: OFF
|
||||
validation_level: 2
|
||||
- name: 🪟 Windows (MSVC - Release)
|
||||
os: windows-latest
|
||||
platform: windows
|
||||
arch: x86_64
|
||||
build_type: Release
|
||||
build_shared: OFF
|
||||
build_test: ON
|
||||
validation_level: 2
|
||||
- name: 🪟 Windows (MSVC, Shared - Release)
|
||||
os: windows-latest
|
||||
platform: windows
|
||||
arch: x86_64
|
||||
build_type: Release
|
||||
build_shared: ON
|
||||
build_test: ON
|
||||
validation_level: 2
|
||||
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Checkout Test Data
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'asmaloney/libE57Format-test-data'
|
||||
path: libE57Format-test-data
|
||||
|
||||
- name: Install Dependencies (macOS)
|
||||
if: matrix.config.os == 'macos-latest'
|
||||
if: matrix.platform == 'macos'
|
||||
run: |
|
||||
brew install ninja xerces-c
|
||||
brew install ccache ninja xerces-c
|
||||
|
||||
- name: Install Dependencies (Ubuntu)
|
||||
if: matrix.config.os == 'ubuntu-latest'
|
||||
- name: Install Dependencies (Linux)
|
||||
if: matrix.platform == 'linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
|
||||
sudo apt-get install -y libxerces-c-dev ninja-build
|
||||
|
||||
- name: Install miniconda (Windows)
|
||||
if: matrix.config.os == 'windows-latest'
|
||||
uses: conda-incubator/setup-miniconda@v2
|
||||
with:
|
||||
auto-update-conda: true
|
||||
channels: conda-forge
|
||||
miniconda-version: 'latest'
|
||||
sudo apt-get install -y ccache libxerces-c-dev ninja-build
|
||||
sudo locale-gen fr_FR
|
||||
|
||||
- name: Install Dependencies (Windows)
|
||||
if: matrix.config.os == 'windows-latest'
|
||||
if: matrix.platform == 'windows'
|
||||
uses: conda-incubator/setup-miniconda@v3
|
||||
with:
|
||||
channels: conda-forge
|
||||
|
||||
- name: Install More Dependencies (Windows)
|
||||
if: matrix.platform == 'windows'
|
||||
shell: bash -el {0}
|
||||
run: |
|
||||
conda install -y ninja xerces-c
|
||||
conda install conda-forge::xerces-c
|
||||
choco upgrade ccache ninja
|
||||
ccache --version | head -n 1
|
||||
echo "ninja $(ninja --version)"
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
max-size: '5G'
|
||||
key: ${{ matrix.os }}-${{ matrix.build_type }}
|
||||
|
||||
- name: Configure MSVC console (Windows)
|
||||
if: matrix.config.os == 'windows-latest'
|
||||
if: matrix.platform == 'windows'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
- name: Set environment for MSVC (Windows)
|
||||
if: matrix.config.os == 'windows-latest'
|
||||
- name: Output conda info (Windows)
|
||||
if: matrix.platform == 'windows'
|
||||
run: |
|
||||
# Set these env vars so cmake picks the correct compiler
|
||||
echo "CXX=cl.exe" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
echo "CC=cl.exe" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
conda info
|
||||
conda list
|
||||
conda config --show-sources
|
||||
conda config --show
|
||||
printenv | sort
|
||||
|
||||
- name: Configure
|
||||
run: >
|
||||
@@ -74,9 +158,16 @@ jobs:
|
||||
-B libE57Format-build
|
||||
-G "Ninja"
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
-DCMAKE_CXX_FLAGS_DEBUG="-g -DE57_MAX_VERBOSE"
|
||||
-DE57_BUILD_SHARED=${{ matrix.build_shared }}
|
||||
-DE57_BUILD_TEST=${{ matrix.build_test }}
|
||||
-DE57_VALIDATION_LEVEL=${{ matrix.validation_level }}
|
||||
-DE57FORMAT_WARNING_AS_ERROR:BOOL=ON
|
||||
-DE57FORMAT_SANITIZE_ALL:BOOL=ON
|
||||
.
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake --build libE57Format-build
|
||||
run: cmake --build libE57Format-build
|
||||
|
||||
- name: Test
|
||||
if: matrix.build_test == 'ON'
|
||||
run: libE57Format-build/testE57
|
||||
|
||||
19
src/3rdParty/libE57Format/.github/workflows/format-check.yml
vendored
Normal file
19
src/3rdParty/libE57Format/.github/workflows/format-check.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: C++ Code Format
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
formatting-check:
|
||||
name: Formatting Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run clang-format style check
|
||||
uses: jidicula/clang-format-action@v4.15.0
|
||||
with:
|
||||
clang-format-version: '18'
|
||||
exclude-regex: 'extern'
|
||||
3
src/3rdParty/libE57Format/.gitignore
vendored
Normal file
3
src/3rdParty/libE57Format/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
build
|
||||
.vscode
|
||||
.cache
|
||||
0
src/3rdParty/libE57Format/.gitmodules
vendored
Normal file
0
src/3rdParty/libE57Format/.gitmodules
vendored
Normal file
42
src/3rdParty/libE57Format/.travis.yml
vendored
42
src/3rdParty/libE57Format/.travis.yml
vendored
File diff suppressed because one or more lines are too long
211
src/3rdParty/libE57Format/CHANGELOG.md
vendored
211
src/3rdParty/libE57Format/CHANGELOG.md
vendored
@@ -1,16 +1,219 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
## 3.3.0 - (in progress)
|
||||
|
||||
## 2.2.1 - (in progress)
|
||||
### Added
|
||||
|
||||
- {cmake} Generate a package version file ([#316](https://github.com/asmaloney/libE57Format/pull/316)) (Thanks SunBlack!)
|
||||
|
||||
### Changed
|
||||
|
||||
- {cmake} Require XercesC 3.2 and remove `USING_STATIC_XERCES` ([#317](https://github.com/asmaloney/libE57Format/pull/317)) (Thanks SunBlack!)
|
||||
|
||||
### Fixed
|
||||
|
||||
- {cmake} Added missing include for GNUInstallDirs ([#315](https://github.com/asmaloney/libE57Format/pull/315)) (Thanks Adrian!)
|
||||
|
||||
If you built without testing on, the cmake files were not installed to the correct location.
|
||||
|
||||
## [3.2.0](https://github.com/asmaloney/libE57Format/releases/tag/v3.2.0) - 2024-06-27
|
||||
|
||||
### Added
|
||||
|
||||
- {cmake} Added `E57_INSTALL_CMAKEDIR` option to override where the cmake files are installed. ([#305](https://github.com/asmaloney/libE57Format/pull/305))
|
||||
|
||||
This defaults to `lib/cmake/E57Format` and the path is relative to `CMAKE_INSTALL_PREFIX`.
|
||||
|
||||
### Changed
|
||||
|
||||
- {cmake} If building as a shared library, set [VERSION](https://cmake.org/cmake/help/v3.15/prop_tgt/VERSION.html) & [SOVERSION](https://cmake.org/cmake/help/v3.15/prop_tgt/SOVERSION.html). ([#304](https://github.com/asmaloney/libE57Format/pull/304))
|
||||
- {cmake} Don't force warnings as errors when building self. ([#299](https://github.com/asmaloney/libE57Format/pull/299))
|
||||
- {cmake} Use git tag in library version for more precision. ([#298](https://github.com/asmaloney/libE57Format/pull/298))
|
||||
- {license} Re-license all my (asmaloney) MIT files to BSL-1.0. It is just easier to have it all under one license. ([#296](https://github.com/asmaloney/libE57Format/pull/296))
|
||||
- {format} Update to clang-format 18 & reformat code. ([#286](https://github.com/asmaloney/libE57Format/pull/286))
|
||||
- Add "E57\_" to macros in E57Exception.h. ([#285](https://github.com/asmaloney/libE57Format/pull/285))
|
||||
- "De-deprecate" methods in **E57SimpleWriter**. These methods can be useful when writing batches. ([#284](https://github.com/asmaloney/libE57Format/pull/284))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Update CRCpp to fix MSVC and MinGW warnings. ([#302](https://github.com/asmaloney/libE57Format/pull/302))
|
||||
- Fix warnings about redefinition of `_LARGEFILE64_SOURCE` and `__LARGE64_FILES` ([#301](https://github.com/asmaloney/libE57Format/pull/301)) (Thanks Niklas!)
|
||||
- Fix building with emscripten. (Note that the project doesn't officially support emscripten.) ([#288](https://github.com/asmaloney/libE57Format/pull/288)) (Thanks maz-1!)
|
||||
- {standard conformance} CompressedVectors always write an index packet. This is required by the standard (9.3.5). ([#295](https://github.com/asmaloney/libE57Format/pull/295))
|
||||
- {standard conformance} **E57SimpleReader** accepts files containing zero scans. ([#283](https://github.com/asmaloney/libE57Format/pull/283))
|
||||
- {cmake} Replace deprecated "exec_program" with "execute_process". ([#282](https://github.com/asmaloney/libE57Format/pull/282))
|
||||
- Fix potential invalid range exceptions when reading integer nodes. ([#278](https://github.com/asmaloney/libE57Format/pull/278))
|
||||
|
||||
## [3.1.1](https://github.com/asmaloney/libE57Format/releases/tag/v3.1.1) - 2023-11-28
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix library version in CMakeLists.txt. (Thanks Olli!)
|
||||
|
||||
## [3.1.0](https://github.com/asmaloney/libE57Format/releases/tag/v3.1.0) - 2023-11-20
|
||||
|
||||
### Added
|
||||
|
||||
- {cmake} New option `E57_RELEASE_LTO` controls whether link-time optimization is on for release builds. It defaults to `ON`. ([#254](https://github.com/asmaloney/libE57Format/pull/254))
|
||||
|
||||
CMake forces "thin" LTO (see [this issue](https://gitlab.kitware.com/cmake/cmake/-/issues/23136)) which is a problem if compiling statically for distribution (e.g. in a package manager). Generally you will only want to turn this off for distributing static release builds.
|
||||
|
||||
### Changed
|
||||
|
||||
- Trying to read a Data3D with zero records which has an ill-formed header will now throw an `ErrorData3DReadInvalidZeroRecords` exception instead of `ErrorInternal`. ([#264](https://github.com/asmaloney/libE57Format/pull/264))
|
||||
> Note that previous versions of this library (and E57RefImpl itself) could write these headers incorrectly. This was also fixed in this release (see below).
|
||||
- {cmake} Remove `E57_VISIBILITY_HIDDEN` option. ([#259](https://github.com/asmaloney/libE57Format/pull/259))
|
||||
|
||||
I cannot get extern templates to work across all of gcc, clang, apple clang, and MSVC when using "hidden" visibility with shared libraries.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix #include to avoid MSVC compilation error with Visual Studio 2017 ([#268](https://github.com/asmaloney/libE57Format/pull/268)) (Thanks Thomas!)
|
||||
- {standard conformance} A compressed vector with 0 records must still write a data packet. ([#266](https://github.com/asmaloney/libE57Format/pull/266))
|
||||
- {standard conformance} Fix reading a compressed vector with 0 points which has an empty data packet. ([#267](https://github.com/asmaloney/libE57Format/pull/267))
|
||||
- {standard conformance} Compressed vectors with an invalid section ID now throw an `ErrorBadCVPacket` exception if `E57_VALIDATION_LEVEL` > 0. ([#265](https://github.com/asmaloney/libE57Format/pull/265))
|
||||
- Fix clang warnings about implicit conversions in _SourceDestBufferImpl.cpp_. Apple's clang doesn't warn about these, but it looks like the official clang releases do. ([#257](https://github.com/asmaloney/libE57Format/pull/257)) (Thanks Martin!)
|
||||
|
||||
## [3.0.2](https://github.com/asmaloney/libE57Format/releases/tag/v3.0.2) - 2023-07-22
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `E57_VERBOSE` build. ([#251](https://github.com/asmaloney/libE57Format/pull/251)) (Thanks Jia!)
|
||||
- {standard conformance} Fix invalid range exception in FloatNode implementation. ([#250](https://github.com/asmaloney/libE57Format/pull/250))
|
||||
- Fix reading of index packets. ([#249](https://github.com/asmaloney/libE57Format/pull/249))
|
||||
- Fix several places where we should be checking for MSVC, not WIN32. ([#248](https://github.com/asmaloney/libE57Format/pull/248))
|
||||
- Fix "unnecessary semicolons" warnings which prevented building with GCC <= 10. ([#241](https://github.com/asmaloney/libE57Format/pull/241)) (Thanks Andre!)
|
||||
|
||||
## [3.0.1](https://github.com/asmaloney/libE57Format/releases/tag/v3.0.1) - 2023-03-15
|
||||
|
||||
### Added
|
||||
|
||||
- {ci} Added an MSVC 32-bit build. ([#235](https://github.com/asmaloney/libE57Format/pull/235))
|
||||
|
||||
### Fixed
|
||||
|
||||
- {cmake} Turn off inter-procedural optimization in debug builds. Link-time optimization can make debugging more difficult. ([#240](https://github.com/asmaloney/libE57Format/pull/240))
|
||||
- {cmake} Don't force a debug postfix if `CMAKE_DEBUG_POSTFIX` is defined.([#239](https://github.com/asmaloney/libE57Format/pull/239))
|
||||
- {cmake} Don't force install locations. This prevents overriding them using `CMAKE_INSTALL_BINDIR` & `CMAKE_INSTALL_LIBDIR`.([#237](https://github.com/asmaloney/libE57Format/pull/237))
|
||||
- Fix warnings which prevented building on 32-bit systems. ([#233](https://github.com/asmaloney/libE57Format/pull/233), [#234](https://github.com/asmaloney/libE57Format/pull/234))
|
||||
|
||||
## [3.0.0](https://github.com/asmaloney/libE57Format/releases/tag/v3.0.0) - 2023-02-23
|
||||
|
||||
There have been _many_ changes around the `Simple API` in this release to fix some problems, avoid potential errors, and simplify the use of the API. Where possible these changes are marked as `deprecated` to be removed later. The compiler will produce warnings for these indicating what needs to change. Other changes could not be marked deprecated but will break the API, requiring code changes. The notable ones are marked with 🚧 below.
|
||||
|
||||
### Added
|
||||
|
||||
- Add address (ASan) and undefined behaviour (UBSan) sanitizers. These are controlled by `E57FORMAT_SANITIZE_ALL`, `E57FORMAT_SANITIZE_ADDRESS` and `E57FORMAT_SANITIZE_ADDRESS`. They are not included when building with MSVC.
|
||||
- Add new `E57Version.h` header for more convenient access to version information. ([#197](https://github.com/asmaloney/libE57Format/pull/197)).
|
||||
- Add `ImageFile::extensionsLookupPrefix()` overload for more concise user code. ([#161](https://github.com/asmaloney/libE57Format/pull/161))
|
||||
- Added a constructor & destructor for **E57SimpleData**'s `Data3DPointsData_t`. This will create all the required buffers based on an `e57::Data3D` struct and handle their cleanup. See the `SimpleWriter` tests for examples. ([#149](https://github.com/asmaloney/libE57Format/pull/149))
|
||||
|
||||
> **Note:** I strongly recommend these new constructors be used to simplify your code and help prevent errors.
|
||||
|
||||
- A new **E57SimpleReader** constructor takes a `ReaderOptions` struct which allows setting the checksum policy.
|
||||
```cpp
|
||||
Reader( const ustring &filePath, const ReaderOptions &options );
|
||||
```
|
||||
- {test} Added testing using [GoogleTest](https://github.com/google/googletest). For details, please see [test/README.md](test/README.md) ([#121](https://github.com/asmaloney/libE57Format/pull/121))
|
||||
- Added `E57Exception::errorStr()` to get the error string directly. ([#128](https://github.com/asmaloney/libE57Format/pull/128))
|
||||
- {cmake} Use [ccache](https://ccache.dev/) if available. ([#129](https://github.com/asmaloney/libE57Format/pull/129))
|
||||
- {ci} Added a CI check for proper clang-formatted code. ([#125](https://github.com/asmaloney/libE57Format/pull/125))
|
||||
|
||||
### Changed
|
||||
|
||||
- Now requires a **[C++14](https://en.cppreference.com/w/cpp/14)** compatible compiler.
|
||||
- Now requires **[CMake](https://cmake.org/) >= 3.15**. ([#205](https://github.com/asmaloney/libE57Format/pull/205))
|
||||
- 🚧 **DEBUG** and **VERBOSE** macros were changed to simplify and clarify:
|
||||
- New `E57_ENABLE_DIAGNOSTIC_OUTPUT` controls the inclusion of the code for the `dump()` functions on nodes. I don't see any real reason to turn this off, but I left the capability in for compatibility.
|
||||
- New `E57_VALIDATION_LEVEL=N` replaces `E57_DEBUG` (N=1) and `E57_MAX_DEBUG` (N=2).
|
||||
- `E57_MAX_VERBOSE` was consolidated with `E57_VERBOSE` since they were essentially the same.
|
||||
- When building itself, warnings are now treated as errors. ([#205](https://github.com/asmaloney/libE57Format/pull/205), [#211](https://github.com/asmaloney/libE57Format/pull/211))
|
||||
- Clean up global const and enum names to use the `e57` namespace and avoid repetition. ([#176](https://github.com/asmaloney/libE57Format/pull/176))
|
||||
- i.e. instead of `e57::E57_STRUCTURE`, we now use `e57::TypeStructure`
|
||||
- {format} Update clang-format rules for clang-format 15. ([#168](https://github.com/asmaloney/libE57Format/pull/168), [#179](https://github.com/asmaloney/libE57Format/pull/179))
|
||||
- Change default checksum policies to an enum. ([#166](https://github.com/asmaloney/libE57Format/pull/166))
|
||||
Old | New
|
||||
--|--
|
||||
CHECKSUM_POLICY_NONE | ChecksumPolicy::None
|
||||
CHECKSUM_POLICY_SPARSE | ChecksumPolicy::Sparse
|
||||
CHECKSUM_POLICY_HALF | ChecksumPolicy::Half
|
||||
CHECKSUM_POLICY_ALL | ChecksumPolicy::All
|
||||
- Avoid implicit conversion in constructors. ([#135](https://github.com/asmaloney/libE57Format/pull/135))
|
||||
- Update [CRCpp](https://github.com/d-bahr/CRCpp) to 1.2. ([#130](https://github.com/asmaloney/libE57Format/pull/130))
|
||||
- **E57Exception** changes ([#118](https://github.com/asmaloney/libE57Format/pull/118)):
|
||||
- mark methods as `noexcept`
|
||||
- use `private` instead of `protected`
|
||||
- Rename **E57Simple**'s `Data3DPointsData` and `Data3DPointsData_d` structs to `Data3DPointsFloat` and `Data3DPointsDouble` respectively. ([#180](https://github.com/asmaloney/libE57Format/pull/180))
|
||||
- 🚧 **E57Simple:** Specifying the node type for cartesian & spherical points, time stamp, and intensity is now explicit using new fields (`pointRangeNodeType`, `angleNodeType`, `timeNodeType`, and `intensityNodeType`) and a new enum (`NumericalNodeType`). ([#178](https://github.com/asmaloney/libE57Format/pull/178))
|
||||
- For examples, please see _test/src/testSimpleWriter.cpp_.
|
||||
- Simplify the **E57SimpleWriter** API with `WriteImage2DData()` for images and `WriteData3DData()` for 3D data. This reduces code, hides complexity, and avoids potential errors. ([#171](https://github.com/asmaloney/libE57Format/pull/171))
|
||||
- As part of this simplification, `WriteData3DData()` will now fill in any missing min/max values for cartesian & spherical points, intensity, and time stamps by looking at the data.([#175](https://github.com/asmaloney/libE57Format/pull/175))
|
||||
- 🚧 **E57Simple:** Intensity now uses `double` instead of `float`. ([#178](https://github.com/asmaloney/libE57Format/pull/178))
|
||||
- 🚧 **E57Simple:** Colours now use `uint16_t` instead of `uint8_t`. ([#167](https://github.com/asmaloney/libE57Format/pull/167))
|
||||
- 🚧 Change **E57SimpleData**'s Data3D field name from `pointsSize` to `pointCount`. ([#164](https://github.com/asmaloney/libE57Format/pull/164))
|
||||
- 🚧 Min/max fields in **E57SimpleData**'s Data3D's point fields were a mix of floats and doubles. Since the fields are doubles, set them all to doubles and use the new `Data3DPointsData_t` constructor to set them properly for floats. ([#153](https://github.com/asmaloney/libE57Format/pull/153))
|
||||
> **Note:** If you were previously relying on these to be floats and are not using the new `Data3DPointsData_t` constructor, you will need to set these.
|
||||
- 🚧 Renamed the [E57_EXT_surface_normals](http://www.libe57.org/E57_EXT_surface_normals.txt) extension's fields in **E57SimpleData**'s `PointStandardizedFieldsAvailable` to be in line with existing code. ([#149](https://github.com/asmaloney/libE57Format/pull/149))
|
||||
- `normalX` renamed to `normalXField`
|
||||
- `normalY` renamed to `normalYField`
|
||||
- `normalZ` renamed to `normalZField`
|
||||
|
||||
### Deprecated
|
||||
|
||||
- `e57::Utilities::getVersions()`. ([#197](https://github.com/asmaloney/libE57Format/pull/197))
|
||||
- `e57::Data3DPointsData` and `e57::Data3DPointsData_d` types. ([#180](https://github.com/asmaloney/libE57Format/pull/180))
|
||||
- Many global const and enum names. The compiler will produce warnings including the replacement symbols (note that enumerators will not produce warnings on C++14, but they will on C++17). ([#176](https://github.com/asmaloney/libE57Format/pull/176))
|
||||
- `e57::Writer::NewImage2D`and `e57::Writer::SetUpData3DPointsData`. ([#171](https://github.com/asmaloney/libE57Format/pull/171))
|
||||
- Old default checksum policies (`CHECKSUM_POLICY_NONE`, `CHECKSUM_POLICY_SPARSE`, `CHECKSUM_POLICY_HALF`, and `CHECKSUM_POLICY_ALL`). ([#166](https://github.com/asmaloney/libE57Format/pull/166))
|
||||
- The old `e57::Reader` constructor taking only `filePath`. ([#139](https://github.com/asmaloney/libE57Format/pull/139))
|
||||
- The old `e57::Writer` constructor taking only `filePath`. ([#117](https://github.com/asmaloney/libE57Format/pull/117))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix several potential divide-by-zero cases. ([#224](https://github.com/asmaloney/libE57Format/pull/224))
|
||||
- {ci} Now builds shared library versions as well. ([#219](https://github.com/asmaloney/libE57Format/pull/219))
|
||||
- {win} Fixes shared library build warnings. ([#215](https://github.com/asmaloney/libE57Format/pull/215), [#216](https://github.com/asmaloney/libE57Format/pull/216), [#217](https://github.com/asmaloney/libE57Format/pull/217))
|
||||
- Fix the code which shortens floating point numbers when converted to strings. The impact of it being incorrect was negligible since it's just the floating point representation in the XML portion of the file. ([#214](https://github.com/asmaloney/libE57Format/pull/214))
|
||||
- Turned on a lot of compiler warnings and fixed them. ([#201](https://github.com/asmaloney/libE57Format/pull/201), [#202](https://github.com/asmaloney/libE57Format/pull/202), [#203](https://github.com/asmaloney/libE57Format/pull/203), [#204](https://github.com/asmaloney/libE57Format/pull/204), [#205](https://github.com/asmaloney/libE57Format/pull/205), [#207](https://github.com/asmaloney/libE57Format/pull/207), [#209](https://github.com/asmaloney/libE57Format/pull/209))
|
||||
- Fix writing floating point numbers when `std::locale::global` is set. ([#174](https://github.com/asmaloney/libE57Format/pull/174))
|
||||
- E57XmlParser: Parse doubles in a locale-independent way. ([#173](https://github.com/asmaloney/libE57Format/pull/173)) (Thanks Hugal31!)
|
||||
- E57SimpleReader: Ensure scaled integer fields are set as best we can when reading. ([#158](https://github.com/asmaloney/libE57Format/pull/158))
|
||||
- Fix the [E57_EXT_surface_normals](http://www.libe57.org/E57_EXT_surface_normals.txt) extension's URI in **E57SimpleWriter**. ([#143](https://github.com/asmaloney/libE57Format/pull/143))
|
||||
- {win} Fix conversion warning when compiling with debug on. ([#124](https://github.com/asmaloney/libE57Format/pull/124))
|
||||
- Add errno detail to `E57_ERROR_OPEN_FAILED` exception. ([#119](https://github.com/asmaloney/libE57Format/pull/119), [#120](https://github.com/asmaloney/libE57Format/pull/120))
|
||||
|
||||
## [2.3.0](https://github.com/asmaloney/libE57Format/releases/tag/v2.3.0) - 2022-10-04
|
||||
|
||||
### Added
|
||||
|
||||
- {cmake} Added `E57_VISIBILITY_HIDDEN` option to control [CXX_VISIBILITY_PRESET](https://cmake.org/cmake/help/latest/prop_tgt/LANG_VISIBILITY_PRESET.html). Defaults to `ON`. ([#104](https://github.com/asmaloney/libE57Format/pull/104)) (Thanks Nigel!)
|
||||
- Added BSD support. ([#99](https://github.com/asmaloney/libE57Format/pull/99)) (Thanks Christophe!)
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated & reorganized the [online API docs](https://asmaloney.github.io/libE57Format-docs/) and changed to a [cleaner theme](https://github.com/jothepro/doxygen-awesome-css).
|
||||
- Change file creation to use _0666_ permissions on [POSIX](https://en.wikipedia.org/wiki/POSIX) systems. ([#105](https://github.com/asmaloney/libE57Format/pull/105)) (Thanks Nigel!)
|
||||
- {cmake} [CXX_VISIBILITY_PRESET](https://cmake.org/cmake/help/latest/prop_tgt/LANG_VISIBILITY_PRESET.html) is now set and `ON` by default. ([#104](https://github.com/asmaloney/libE57Format/pull/104)) (Thanks Nigel!)
|
||||
- A new **E57SimpleWriter** constructor takes a `WriterOptions` struct which allows setting the file's GUID.
|
||||
```cpp
|
||||
Writer( const ustring &filePath, const WriterOptions &options );
|
||||
```
|
||||
The old constructor taking only `coordinateMetadata` is deprecated and will be removed in the future. ([#96](https://github.com/asmaloney/libE57Format/pull/96)) (Thanks Nigel!)
|
||||
- Change `E57_DEBUG`, `E57_MAX_DEBUG`, `E57_VERBOSE`, `E57_MAX_VERBOSE`, `E57_WRITE_CRAZY_PACKET_MODE` from **#defines** to cmake options. ([#80](https://github.com/asmaloney/libE57Format/pull/80)) (Thanks Nigel!)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix **E57SimpleWriter**'s writing of invalid quaternions. It now defaults to the identity quaternion. ([#108](https://github.com/asmaloney/libE57Format/pull/108)) (Thanks Nigel!)
|
||||
- Fix **E57SimpleReader** to handle missing `images2D` and `isAtomicClockReferenced` nodes. ([#90](https://github.com/asmaloney/libE57Format/pull/90)) (Thanks Olli!)
|
||||
- Fix **BitpackIntegerDecoder** sometimes reading past end of input buffer. ([#87](https://github.com/asmaloney/libE57Format/pull/87)) (Thanks Nigel!)
|
||||
- Fix compilation when some debug options are set. ([#81](https://github.com/asmaloney/libE57Format/pull/81), [#82](https://github.com/asmaloney/libE57Format/pull/82), [#84](https://github.com/asmaloney/libE57Format/pull/84)) (Thanks Nigel!)
|
||||
- Fix compilation with [musl libc](https://musl.libc.org/) ([#70](https://github.com/asmaloney/libE57Format/pull/70)) (Thanks Dimitri!)
|
||||
- Add missing include for [GCC 11](https://gcc.gnu.org/gcc-11/porting_to.html#header-dep-changes) ([#68](https://github.com/asmaloney/libE57Format/pull/68)) (Thanks bartoszek!)
|
||||
|
||||
**Note:** The next release will be 3.0 and will require a [C++14](https://en.cppreference.com/w/cpp/14) compiler.
|
||||
|
||||
## [2.2.0](https://github.com/asmaloney/libE57Format/releases/tag/v2.2.0) - 2021-04-01
|
||||
|
||||
### Added
|
||||
@@ -35,7 +238,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
### Other
|
||||
|
||||
- Removed all internal usage of dynamic_cast<>. ([#39](https://github.com/asmaloney/libE57Format/pull/39)) (Thanks Jiri!)
|
||||
- Split classes out from E57FormatImpl.[h,cpp] intot their own files.
|
||||
- Split classes out from E57FormatImpl.[h,cpp] into their own files.
|
||||
|
||||
## [2.1.0](https://github.com/asmaloney/libE57Format/releases/tag/v2.1) - 2020-04-01
|
||||
|
||||
|
||||
225
src/3rdParty/libE57Format/CMakeLists.txt
vendored
225
src/3rdParty/libE57Format/CMakeLists.txt
vendored
@@ -3,8 +3,8 @@
|
||||
#
|
||||
# Use git blame to see all the changes and who has contributed.
|
||||
#
|
||||
# Copyright 2018-2023 Andy Maloney <asmaloney@gmail.com>
|
||||
# Original work Copyright 2010-2012 Roland Schwarz, Riegl LMS GmbH
|
||||
# Modified work Copyright 2018-2020 Andy Maloney <asmaloney@gmail.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person or organization
|
||||
# obtaining a copy of the software and accompanying documentation covered by
|
||||
@@ -28,10 +28,12 @@
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
# DEALINGS IN THE SOFTWARE.
|
||||
|
||||
cmake_minimum_required( VERSION 3.10.0 )
|
||||
cmake_minimum_required( VERSION 3.15 )
|
||||
|
||||
# Set a private module find path
|
||||
set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/" )
|
||||
set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
|
||||
|
||||
message( STATUS "Using CMake ${CMAKE_VERSION}" )
|
||||
|
||||
project( E57Format
|
||||
DESCRIPTION
|
||||
@@ -39,10 +41,20 @@ project( E57Format
|
||||
LANGUAGES
|
||||
CXX
|
||||
VERSION
|
||||
2.2.1
|
||||
3.2.0
|
||||
)
|
||||
|
||||
string( TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPERCASE )
|
||||
|
||||
# Creates a build tag which is used in the REVISION_ID
|
||||
# e.g. "x86_64-darwin-AppleClang140"
|
||||
include( Tags )
|
||||
include( GitInfo )
|
||||
|
||||
# Collect all our current git info using:
|
||||
# https://github.com/cppmf/GitInfo.cmake
|
||||
GitInfo( ${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
# GitInfoReport()
|
||||
|
||||
# Check if we are building ourself or being included and use this to set some defaults
|
||||
if ( ${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME} )
|
||||
@@ -65,7 +77,7 @@ if ( E57_BUILDING_SELF )
|
||||
endif()
|
||||
|
||||
find_package( Threads REQUIRED )
|
||||
find_package( XercesC REQUIRED )
|
||||
find_package( XercesC 3.2 REQUIRED )
|
||||
|
||||
option( E57_BUILD_SHARED
|
||||
"Compile E57Format as a shared library"
|
||||
@@ -77,105 +89,116 @@ if( BUILD_SHARED_LIBS )
|
||||
endif()
|
||||
|
||||
#########################################################################################
|
||||
|
||||
# Various levels of cross checking and verification in the code.
|
||||
# Cross checking and runtime verification in the code.
|
||||
# The extra code does not change the file contents.
|
||||
# Recommend that E57_DEBUG remain defined even for production versions.
|
||||
# E57_VALIDATION_LEVEL=0 off
|
||||
# E57_VALIDATION_LEVEL=1 basic
|
||||
# E57_VALIDATION_LEVEL=2 deep (implies basic) - checks at the packet level, so it will be slower
|
||||
set( E57_VALIDATION_LEVEL "1" CACHE STRING "Runtime validation level (0 = OFF, 1 = basic, 2 = deep)" )
|
||||
|
||||
option( E57_DEBUG "Compile library with minimal debug checking" ON )
|
||||
option( E57_MAX_DEBUG "Compile library with maximum debug checking" OFF )
|
||||
# Output detailed logging while processing.
|
||||
option( E57_VERBOSE "Compile library with verbose logging" OFF )
|
||||
|
||||
# Various levels of printing to the console of what is going on in the code.
|
||||
# Optional
|
||||
|
||||
option( E57_VERBOSE "Compile library with verbose logging" OFF )
|
||||
option( E57_MAX_VERBOSE "Compile library with maximum verbose logging" OFF )
|
||||
# Enable/disable code which dumps detailed node info to std::ostream. (See NodeImpl::dump())
|
||||
# Instead of always including this code, it is an option for backwards compatibility.
|
||||
# The only real reason to turn this off would be for slightly smaller binaries.
|
||||
option( E57_ENABLE_DIAGNOSTIC_OUTPUT "Include code for diagnostic output using dump() on nodes" ON )
|
||||
|
||||
# Enable writing packets that are correct but will stress the reader.
|
||||
|
||||
option( E57_WRITE_CRAZY_PACKET_MODE "Compile library to enable reader-stressing packets" OFF )
|
||||
|
||||
# Other compile options
|
||||
|
||||
# Link-time optiomization
|
||||
# CMake forces "thin" LTO (see https://gitlab.kitware.com/cmake/cmake/-/issues/23136)
|
||||
# which is a problem if compiling statically for distribution (e.g. in a package manager).
|
||||
# Generally you will only want to turn this off for distributing static release builds.
|
||||
option( E57_RELEASE_LTO "Compile release library with link-time optimization" ON )
|
||||
|
||||
#########################################################################################
|
||||
|
||||
set( revision_id "${PROJECT_NAME}-${PROJECT_VERSION}-${${PROJECT_NAME}_BUILD_TAG}" )
|
||||
message( STATUS "[E57] Revision ID: ${revision_id}" )
|
||||
|
||||
# Need to explicitly set the source files to add_library()
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
|
||||
file(GLOB E57Format_SOURCES src/[^.]*.cpp)
|
||||
set( REVISION_ID "${PROJECT_NAME}-${PROJECT_VERSION}-${${PROJECT_NAME}_BUILD_TAG}" )
|
||||
if ( GIT_LATEST_TAG )
|
||||
set( REVISION_ID "${REVISION_ID} (git ${GIT_LATEST_TAG})" )
|
||||
endif()
|
||||
message( STATUS "[${PROJECT_NAME}] Revision ID: ${REVISION_ID}" )
|
||||
|
||||
# Target
|
||||
if ( E57_BUILD_SHARED )
|
||||
message( STATUS "[E57] Building shared library" )
|
||||
message( STATUS "[${PROJECT_NAME}] Building shared library" )
|
||||
add_library( E57Format SHARED ${E57Format_SOURCES})
|
||||
else()
|
||||
message( STATUS "[E57] Building static library" )
|
||||
message( STATUS "[${PROJECT_NAME}] Building static library" )
|
||||
add_library( E57Format STATIC ${E57Format_SOURCES})
|
||||
endif()
|
||||
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT ipo_ok OUTPUT ipo_msg)
|
||||
if(NOT ipo_ok)
|
||||
set(E57_RELEASE_LTO Off)
|
||||
endif()
|
||||
|
||||
include( E57ExportHeader )
|
||||
include( GitUpdate )
|
||||
|
||||
# Main sources and includes
|
||||
add_subdirectory( extern/CRCpp )
|
||||
add_subdirectory( include )
|
||||
add_subdirectory( src )
|
||||
|
||||
include( ClangFormat )
|
||||
|
||||
# Target properties
|
||||
set_target_properties( E57Format
|
||||
PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
CXX_EXTENSIONS NO
|
||||
DEBUG_POSTFIX "-d"
|
||||
CXX_EXTENSIONS NO
|
||||
EXPORT_COMPILE_COMMANDS ON
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
INTERPROCEDURAL_OPTIMIZATION ${E57_RELEASE_LTO}
|
||||
INTERPROCEDURAL_OPTIMIZATION_DEBUG OFF
|
||||
)
|
||||
|
||||
if ( NOT DEFINED CMAKE_DEBUG_POSTFIX )
|
||||
set_target_properties( E57Format
|
||||
PROPERTIES
|
||||
DEBUG_POSTFIX "-d"
|
||||
)
|
||||
endif()
|
||||
|
||||
if ( E57_BUILD_SHARED )
|
||||
set_target_properties( E57Format
|
||||
PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
)
|
||||
endif()
|
||||
|
||||
target_compile_features( ${PROJECT_NAME}
|
||||
PRIVATE
|
||||
cxx_std_14
|
||||
)
|
||||
|
||||
# Warnings
|
||||
include( CompilerWarnings )
|
||||
|
||||
# Check our validation level
|
||||
string( STRIP "${E57_VALIDATION_LEVEL}" E57_VALIDATION_LEVEL )
|
||||
if ( NOT E57_VALIDATION_LEVEL MATCHES "^[0-2]$" )
|
||||
message( FATAL_ERROR "[${PROJECT_NAME}] E57_VALIDATION_LEVEL should be 0-2: '${E57_VALIDATION_LEVEL}'" )
|
||||
else()
|
||||
message( STATUS "[${PROJECT_NAME}] Setting validation level to ${E57_VALIDATION_LEVEL}" )
|
||||
endif ()
|
||||
|
||||
# Target definitions
|
||||
target_compile_definitions( E57Format
|
||||
PRIVATE
|
||||
CRCPP_USE_CPP11
|
||||
CRCPP_BRANCHLESS
|
||||
REVISION_ID="${revision_id}"
|
||||
REVISION_ID="${REVISION_ID}"
|
||||
E57_VALIDATION_LEVEL=${E57_VALIDATION_LEVEL}
|
||||
$<$<BOOL:${E57_ENABLE_DIAGNOSTIC_OUTPUT}>:E57_ENABLE_DIAGNOSTIC_OUTPUT>
|
||||
$<$<BOOL:${E57_VERBOSE}>:E57_VERBOSE>
|
||||
$<$<BOOL:${E57_WRITE_CRAZY_PACKET_MODE}>:E57_WRITE_CRAZY_PACKET_MODE>
|
||||
)
|
||||
|
||||
if ( E57_DEBUG )
|
||||
target_compile_definitions( E57Format PRIVATE E57_DEBUG )
|
||||
endif()
|
||||
|
||||
if ( E57_MAX_DEBUG )
|
||||
target_compile_definitions( E57Format PRIVATE E57_MAX_DEBUG )
|
||||
endif()
|
||||
|
||||
if ( E57_VERBOSE )
|
||||
target_compile_definitions( E57Format PRIVATE E57_VERBOSE )
|
||||
endif()
|
||||
|
||||
if ( E57_MAX_VERBOSE )
|
||||
target_compile_definitions( E57Format PRIVATE E57_MAX_VERBOSE )
|
||||
endif()
|
||||
|
||||
if ( E57_WRITE_CRAZY_PACKET_MODE )
|
||||
target_compile_definitions( E57Format PRIVATE E57_WRITE_CRAZY_PACKET_MODE )
|
||||
endif()
|
||||
|
||||
if ( WIN32 )
|
||||
option( USING_STATIC_XERCES "Turn on if you are linking with Xerces as a static lib" OFF )
|
||||
if ( USING_STATIC_XERCES )
|
||||
target_compile_definitions( E57Format
|
||||
PUBLIC
|
||||
XERCES_STATIC_LIBRARY
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Suppress all warnings for this specific 3rd-party target
|
||||
target_compile_options(E57Format PRIVATE
|
||||
$<$<CXX_COMPILER_ID:GNU,Clang>:-w>
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/w>
|
||||
)
|
||||
# sanitizers
|
||||
include( Sanitizers )
|
||||
|
||||
# Target Libraries
|
||||
target_link_libraries( E57Format PRIVATE XercesC::XercesC )
|
||||
@@ -186,21 +209,57 @@ install(
|
||||
E57Format
|
||||
EXPORT
|
||||
E57Format-export
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
# CMake package files
|
||||
#install(
|
||||
# EXPORT
|
||||
# E57Format-export
|
||||
# DESTINATION lib/cmake/E57Format
|
||||
#)
|
||||
# ccache
|
||||
# Turns on ccache if found
|
||||
include( ccache )
|
||||
|
||||
#install(
|
||||
# FILES
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/cmake/e57format-config.cmake
|
||||
# DESTINATION
|
||||
# lib/cmake/E57Format
|
||||
#)
|
||||
# Formatting
|
||||
include( ClangFormat )
|
||||
|
||||
# Testing
|
||||
option( E57_BUILD_TEST
|
||||
"Build tests"
|
||||
${E57_BUILDING_SELF}
|
||||
)
|
||||
|
||||
if ( E57_BUILD_TEST )
|
||||
message( STATUS "[${PROJECT_NAME}] Testing enabled" )
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_subdirectory( test )
|
||||
endif()
|
||||
|
||||
# CMake package files
|
||||
include( GNUInstallDirs )
|
||||
set( E57_INSTALL_CMAKEDIR
|
||||
"${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
|
||||
CACHE STRING
|
||||
"Install path for ${PROJECT_NAME} CMake files"
|
||||
)
|
||||
|
||||
message( STATUS "[${PROJECT_NAME}] CMake files install to ${CMAKE_INSTALL_PREFIX}/${E57_INSTALL_CMAKEDIR}" )
|
||||
|
||||
install(
|
||||
EXPORT
|
||||
E57Format-export
|
||||
DESTINATION
|
||||
"${E57_INSTALL_CMAKEDIR}"
|
||||
)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file (
|
||||
e57format-config-version.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/e57format-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/e57format-config-version.cmake
|
||||
DESTINATION
|
||||
"${E57_INSTALL_CMAKEDIR}"
|
||||
)
|
||||
|
||||
32
src/3rdParty/libE57Format/CONTRIBUTING.md
vendored
32
src/3rdParty/libE57Format/CONTRIBUTING.md
vendored
@@ -1,21 +1,37 @@
|
||||
# How To Contribute
|
||||
|
||||
## Code Changes
|
||||
These are some of the things you can do to contribute to the project:
|
||||
|
||||
## 💰 Financial
|
||||
|
||||
Given that I'm an independent developer without funding, financial support is appreciated. If you would like to support the project financially (especially if you sell a product which uses this library), you can use the [sponsors page](https://github.com/sponsors/asmaloney) for one-off or recurring support, or we can arrange <a href="mailto:asmaloney@gmail.com?subject=libE57Format B2B Sponsorship">B2B invoicing</a> of some kind. Thank you!
|
||||
|
||||
## ✍ Write About The Project
|
||||
|
||||
If you find the project useful, spread the word! Articles, mastodon posts, tweets, blog posts, instagram photos - whatever you're into. Please include a referral back to the repository page: https://github.com/asmaloney/libE57Format
|
||||
|
||||
## ⭐️ Add a Star
|
||||
|
||||
If you found this project useful, please consider starring it! It helps me gauge how useful this project is.
|
||||
|
||||
## ☝ Raise Issues
|
||||
|
||||
If you run into something which doesn't work as expected, raising [an issue](https://github.com/asmaloney/libE57Format/issues) with all the relevant information to reproduce it would be helpful.
|
||||
|
||||
## 🐞 Bug Fixes & 🧪 New Things
|
||||
|
||||
I am happy to review any [pull requests](https://github.com/asmaloney/libE57Format/pulls). Please keep them as short as possible. Each pull request should be atomic and only address one issue. This helps with the review process.
|
||||
|
||||
Note that I will not accept everything, but I welcome discussion. If you are proposing a big change, please raise it as [an issue](https://github.com/asmaloney/libE57Format/issues) first for discussion.
|
||||
|
||||
### Formatting
|
||||
|
||||
This project uses [clang-format](https://clang.llvm.org/docs/ClangFormat.html) to format the code. There is a cmake target (_format_) - which runs _clang-format_ on the source files. After changes have been made, and before you submit your pull request, please run the following:
|
||||
This project uses [clang-format](https://clang.llvm.org/docs/ClangFormat.html) to format the code. There is a cmake target (_e57-clang-format_) - which runs _clang-format_ on the source files. After changes have been made, and before you submit your pull request, please run the following:
|
||||
|
||||
```sh
|
||||
cmake --build . --target format
|
||||
cmake --build . --target e57-clang-format
|
||||
```
|
||||
|
||||
## Documentation
|
||||
## 📖 Documentation
|
||||
|
||||
The [documentation](https://github.com/asmaloney/libE57Format) is a bit old and could use some lovin'. You can submit changes over in the [libE57Format-docs](https://github.com/asmaloney/libE57Format-docs) repository.
|
||||
|
||||
## Financial
|
||||
|
||||
If you would like to support the project financially, you can use the **Sponsor** button at the top of the [libE57Format](https://github.com/asmaloney/libE57Format) repository page.
|
||||
|
||||
156
src/3rdParty/libE57Format/README.md
vendored
156
src/3rdParty/libE57Format/README.md
vendored
@@ -1,53 +1,159 @@
|
||||
# libE57Format
|
||||
|
||||
[](https://travis-ci.org/asmaloney/libE57Format)
|
||||
[](https://github.com/asmaloney/libE57Format/releases/latest) [](https://asmaloney.github.io/libE57Format-docs/) [](LICENSE) 
|
||||
|
||||
A library to provide read & write support for the E57 file format.
|
||||
|
||||
This is a fork of [E57RefImpl](https://sourceforge.net/projects/e57-3d-imgfmt/) v1.1.332. The original source is from [E57RefImpl 1.1.332](https://sourceforge.net/projects/e57-3d-imgfmt/files/E57Refimpl-src/) and then everything was stripped out except the main implementation for reading and writing E57.
|
||||
|
||||
This version also removes the dependency on [Boost](https://www.boost.org/) and requires C++11.
|
||||
|
||||
Many, many other changes were made prior to the first release of this fork. See the [CHANGELOG](CHANGELOG.md) and git history for details.
|
||||
libE57Format is a C++ library which provides read & write support for the ASTM-standard [E57 file format](https://www.astm.org/e2807-11r19e01.html) on Linux, macOS, and Windows. E57 files store 3D point cloud data (produced by 3D imaging systems such as laser scanners), attributes associated with 3D point data (color & intensity), and 2D images (photos taken using a 3D imaging system).
|
||||
|
||||
## Documentation
|
||||
|
||||
The doxygen-generated documentation may be [found here](https://asmaloney.github.io/libE57Format-docs/). These docs are generated and saved in the [libE57Format-docs](https://github.com/asmaloney/libE57Format-docs) repo.
|
||||
|
||||
## Contributing
|
||||
## Commercial Use
|
||||
|
||||
Please see [CONTRIBUTING](CONTRIBUTING.md).
|
||||
If you are using this library in commercial software, please [contribute to the project](/CONTRIBUTING.md).
|
||||
|
||||
## Why Fork?
|
||||
Of course the open source license allows you to just take and not give anything back. It is perfectly Legal, but it is not Right and it's not good for the project.
|
||||
|
||||
The E57RefImpl code hasn't been touched in years and I wanted to make changes to compile this library with macOS. Forking it gives me a bit more freedom to update the code and make changes as required.
|
||||
Over the many years I've worked on this library, I have received precisely _zero_ contributions (PRs, documentation updates, improved testing, financial support) from the many million/billion-dollar companies who use it in their software.
|
||||
|
||||
I changed the name of the project so that it is not confused with the **E57RefImpl** project.
|
||||
The more companies that leech on Open Source instead of nurturing it, the less healthy & viable the ecosystem is.
|
||||
|
||||
I have also changed the main include file's name from `E57Foundation.h` to `E57Format.h` to make sure there is no inclusion confusion.
|
||||
## Requirements
|
||||
|
||||
Versions of **libE57Format** started at 2.0.
|
||||
- a [C++14](https://en.cppreference.com/w/cpp/14) compatible compiler
|
||||
- [CMake](https://cmake.org/) >= 3.15
|
||||
- [clang-format](https://clang.llvm.org/docs/ClangFormat.html) for code formatting
|
||||
- (_optional_) [ccache](https://ccache.dev/) to speed up rebuilds
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [Xerces-C++](https://xerces.apache.org/xerces-c/) (for parsing XML)
|
||||
|
||||
### Installing Dependencies On Linux (Ubuntu)
|
||||
|
||||
```sh
|
||||
$ sudo apt install libxerces-c-dev clang-format
|
||||
```
|
||||
|
||||
### Installing Dependencies On macOS (homebrew)
|
||||
|
||||
```sh
|
||||
$ brew install ccache clang-format xerces-c
|
||||
```
|
||||
|
||||
## Build, Install, & Test
|
||||
|
||||
Here's how you build & install a release version with the defaults:
|
||||
|
||||
```
|
||||
$ cmake -B E57-build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=E57-install libE57Format
|
||||
$ cmake --build E57-build --parallel
|
||||
$ cmake --install E57-build
|
||||
```
|
||||
|
||||
If CMake can't find the xerces-c library, you can set [CMAKE_PREFIX_PATH](https://cmake.org/cmake/help/latest/variable/CMAKE_PREFIX_PATH.html) to point at it.
|
||||
|
||||
```
|
||||
$ cmake -B E57-build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=E57-install \
|
||||
-DCMAKE_PREFIX_PATH=/path/to/xerces-c \
|
||||
libE57Format
|
||||
```
|
||||
|
||||
Once the library is built, you can run the tests like this:
|
||||
|
||||
```
|
||||
$ cd E57-build
|
||||
$ ./test/testE57
|
||||
[==========] Running 36 tests from 8 test suites.
|
||||
[----------] Global test environment set-up.
|
||||
[----------] 1 test from TestData
|
||||
[ RUN ] TestData.RepoExists
|
||||
...
|
||||
```
|
||||
|
||||
See [test/README](test/README.md) for details about testing and the test data.
|
||||
|
||||
## 🍴 Fork (2018)
|
||||
|
||||
This is a fork of [E57RefImpl](https://sourceforge.net/projects/e57-3d-imgfmt/). The original source is from [E57RefImpl 1.1.332](https://sourceforge.net/projects/e57-3d-imgfmt/files/E57Refimpl-src/).
|
||||
|
||||
The original code had not been touched in several years and I wanted to make changes to compile it on macOS. Forking it gave me more freedom to update the code and make changes as required. Everything was stripped out except the main implementation for reading & writing E57 files.
|
||||
|
||||
- I changed the name of the project so that it is not confused with the **E57RefImpl** project.
|
||||
- I changed the main include file's name from `E57Foundation.h` to `E57Format.h` to make sure there is no inclusion confusion.
|
||||
- Versions of **libE57Format** started at 2.0.
|
||||
- I fixed it to compile and run on macOS.
|
||||
- It no longer depends on [Boost](https://www.boost.org/).
|
||||
- It now requires [C++14](https://en.cppreference.com/w/cpp/14). (Version 2.x required [C++11](https://en.cppreference.com/w/cpp/11).)
|
||||
|
||||
Many, many other changes were made prior to the first release of this fork, and it has diverged significantly since. See the [CHANGELOG](CHANGELOG.md) and git history for details.
|
||||
|
||||
### E57Simple API
|
||||
|
||||
Since the original fork, [Jiri Hörner](https://github.com/ptc-jhoerner) has added the E57Simple API from the old reference implementation and updated it.
|
||||
[Jiri Hörner](https://github.com/ptc-jhoerner) added the E57Simple API from the old reference implementation and updated it.
|
||||
|
||||
### Tools
|
||||
This _Simple API_ has evolved since this original port to fix some problems and to make it more foolproof & easier to use. Please see the [CHANGELOG](CHANGELOG.md) for version 3.
|
||||
|
||||
[Ryan Baumann](https://github.com/ryanfb) has updated the `e57unpack` and `e57validate` tools to work with **libE57Format**. You can find them in the [e57tools](https://github.com/ryanfb/e57tools) repo.
|
||||
## Projects Using libE57Format
|
||||
|
||||
- [AliceVision](https://github.com/alicevision/AliceVision)
|
||||
- [CloudCompare](https://github.com/CloudCompare/CloudCompare)
|
||||
- [MeshLab](https://github.com/cnr-isti-vclab/meshlab)
|
||||
- [pye57](https://github.com/davidcaron/pye57)
|
||||
|
||||
These projects use hard forks of libE57Format:
|
||||
|
||||
- [FreeCAD](https://github.com/FreeCAD/FreeCAD)
|
||||
- [PDAL](https://github.com/PDAL/PDAL)
|
||||
|
||||
There are also many commercial products using libE57Format. If any of them would like to sponsor the project and be listed here, please <a href="mailto:asmaloney@gmail.com?subject=libE57Format Sponsorship">contact Andy</a>.
|
||||
|
||||
## How To Contribute
|
||||
|
||||
These are some of the things you can do to contribute to the project:
|
||||
|
||||
### 💰 Financial
|
||||
|
||||
Given that I'm an independent developer without funding, financial support is appreciated. If you would like to support the project financially (especially if you sell a product which uses this library), you can use the [sponsors page](https://github.com/sponsors/asmaloney) for one-off or recurring support, or we can arrange <a href="mailto:asmaloney@gmail.com?subject=libE57Format B2B Sponsorship">B2B invoicing</a> of some kind. Thank you!
|
||||
|
||||
### ✍ Write About The Project
|
||||
|
||||
If you find the project useful, spread the word! Articles, mastodon posts, tweets, blog posts, instagram photos - whatever you're into. Please include a referral back to the repository page: https://github.com/asmaloney/libE57Format
|
||||
|
||||
### ⭐️ Add a Star
|
||||
|
||||
If you found this project useful, please consider starring it! It helps me gauge how useful this project is.
|
||||
|
||||
### ☝ Raise Issues
|
||||
|
||||
If you run into something which doesn't work as expected, raising [an issue](https://github.com/asmaloney/libE57Format/issues) with all the relevant information to reproduce it would be helpful.
|
||||
|
||||
### 🐞 Bug Fixes & 🧪 New Things
|
||||
|
||||
I am happy to review any [pull requests](https://github.com/asmaloney/libE57Format/pulls). Please keep them as short as possible. Each pull request should be atomic and only address one issue. This helps with the review process.
|
||||
|
||||
Note that I will not accept everything, but I welcome discussion. If you are proposing a big change, please raise it as [an issue](https://github.com/asmaloney/libE57Format/issues) first for discussion.
|
||||
|
||||
#### Formatting
|
||||
|
||||
This project uses [clang-format](https://clang.llvm.org/docs/ClangFormat.html) to format the code. There is a cmake target (_e57-clang-format_) - which runs _clang-format_ on the source files. After changes have been made, and before you submit your pull request, please run the following:
|
||||
|
||||
```sh
|
||||
cmake --build . --target e57-clang-format
|
||||
```
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
The [documentation](https://github.com/asmaloney/libE57Format) is a bit old and could use some lovin'. You can submit changes over in the [libE57Format-docs](https://github.com/asmaloney/libE57Format-docs) repository.
|
||||
|
||||
## License
|
||||
|
||||
This project as a whole is licensed under the [**BSL-1.0**](https://opensource.org/licenses/BSL-1.0) license - see the [LICENSE](LICENSE.md) file for details.
|
||||
This project is licensed under the [**BSL-1.0** license](https://opensource.org/licenses/BSL-1.0) - see the [LICENSE](LICENSE.md) file for details.
|
||||
|
||||
Individual source files may contain the following tag instead of the full license text:
|
||||
|
||||
SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
Some CMake files are licensed under the **MIT** license - see the [LICENSE-MIT](LICENSE-MIT.txt) file for details.
|
||||
|
||||
These files contain the following tag instead of the full license text:
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
Using SPDX enables machine processing of license information based on the [SPDX License Identifiers](https://spdx.org/ids) and makes it easier for developers to see at a glance which license they are dealing with.
|
||||
|
||||
32
src/3rdParty/libE57Format/cmake/ClangFormat.cmake
vendored
Normal file
32
src/3rdParty/libE57Format/cmake/ClangFormat.cmake
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# Copyright 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
find_program( E57_CLANG_FORMAT_PROGRAM NAMES clang-format )
|
||||
|
||||
if ( E57_CLANG_FORMAT_PROGRAM )
|
||||
message( STATUS "[${PROJECT_NAME}] Using clang-format: ${E57_CLANG_FORMAT_PROGRAM}" )
|
||||
|
||||
get_target_property( e57_sources ${PROJECT_NAME} SOURCES )
|
||||
|
||||
# Remove some files from the list
|
||||
list( FILTER e57_sources EXCLUDE REGEX ".*/E57Export.h" )
|
||||
list( FILTER e57_sources EXCLUDE REGEX ".*/extern/.*" )
|
||||
|
||||
# Get list of test files. We cannot use get_target_property here
|
||||
# since we will not have a target if E57_BUILD_TEST is off.
|
||||
file( GLOB e57_test_sources
|
||||
LIST_DIRECTORIES false
|
||||
CONFIGURE_DEPENDS
|
||||
${PROJECT_SOURCE_DIR}/test/include/*.h
|
||||
${PROJECT_SOURCE_DIR}/test/src/*.cpp
|
||||
)
|
||||
|
||||
list( APPEND e57_sources ${e57_test_sources} )
|
||||
|
||||
add_custom_target( e57-clang-format
|
||||
COMMAND ${E57_CLANG_FORMAT_PROGRAM} --style=file -i ${e57_sources}
|
||||
COMMENT "Running clang-format..."
|
||||
COMMAND_EXPAND_LISTS
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
112
src/3rdParty/libE57Format/cmake/CompilerWarnings.cmake
vendored
Normal file
112
src/3rdParty/libE57Format/cmake/CompilerWarnings.cmake
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# Copyright 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
string( TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPERCASE )
|
||||
|
||||
if ( NOT MSVC )
|
||||
option( ${PROJECT_NAME_UPPERCASE}_WARN_EVERYTHING "Turn on all warnings (not recommended - used for lib development)" OFF )
|
||||
endif()
|
||||
|
||||
option( ${PROJECT_NAME_UPPERCASE}_WARNING_AS_ERROR "Treat warnings as errors" OFF )
|
||||
|
||||
# Set some helper variables for readability
|
||||
set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
|
||||
set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" )
|
||||
set( compiler_is_msvc "$<CXX_COMPILER_ID:MSVC>" )
|
||||
|
||||
target_compile_options( ${PROJECT_NAME}
|
||||
PRIVATE
|
||||
# MSVC only
|
||||
$<${compiler_is_msvc}:
|
||||
/W4
|
||||
/w14263 # 'function': member function does not override any base class virtual member function
|
||||
/w14296 # 'operator': expression is always 'boolean_value'
|
||||
/w14311 # 'variable': pointer truncation from 'type1' to 'type2'
|
||||
/w14545 # expression before comma evaluates to a function which is missing an argument list
|
||||
/w14546 # function call before comma missing argument list
|
||||
/w14547 # 'operator': operator before comma has no effect; expected operator with side-effect
|
||||
/w14549 # 'operator': operator before comma has no effect; did you intend 'operator'?
|
||||
/w14619 # pragma warning: there is no warning number 'number'
|
||||
/w14640 # thread un-safe static member initialization
|
||||
/w14905 # wide string literal cast to 'LPSTR'
|
||||
/w14906 # string literal cast to 'LPWSTR'
|
||||
|
||||
/wd4251 # 'type' : class 'type1' needs to have dll-interface to be used by clients of class 'type2'
|
||||
>
|
||||
# Clang and GNU common options
|
||||
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:
|
||||
-Wall
|
||||
-Wcast-align
|
||||
-Wextra
|
||||
-Wformat=2
|
||||
-Wnon-virtual-dtor
|
||||
-Wnull-dereference
|
||||
-Woverloaded-virtual
|
||||
-Wpedantic
|
||||
-Wshadow
|
||||
-Wunused
|
||||
>
|
||||
# Clang only
|
||||
$<${compiler_is_clang}:
|
||||
-Wdocumentation
|
||||
-Wno-documentation-deprecated-sync # because enumerator [[deprecated]] attribute is C++17
|
||||
>
|
||||
# GNU only
|
||||
$<${compiler_is_gnu}:
|
||||
-Wduplicated-branches
|
||||
-Wduplicated-cond
|
||||
-Wlogical-op
|
||||
>
|
||||
)
|
||||
|
||||
# Turn on (almost) all warnings on Clang, Apple Clang, and GNU.
|
||||
# Useful for internal development, but too noisy for general development.
|
||||
function( set_warn_everything )
|
||||
message( STATUS "[${PROJECT_NAME}] Turning on (almost) all warnings")
|
||||
|
||||
target_compile_options( ${PROJECT_NAME}
|
||||
PRIVATE
|
||||
# Clang and GNU
|
||||
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:
|
||||
-Weverything
|
||||
-Wno-c++98-compat
|
||||
-Wno-c++98-compat-pedantic
|
||||
-Wno-padded
|
||||
>
|
||||
# Clang only
|
||||
$<${compiler_is_clang}:
|
||||
-Wno-documentation-deprecated-sync # because enumerator [[deprecated]] attribute is C++17
|
||||
>
|
||||
)
|
||||
endfunction()
|
||||
|
||||
if ( NOT MSVC AND ${PROJECT_NAME_UPPERCASE}_WARN_EVERYTHING )
|
||||
set_warn_everything()
|
||||
endif()
|
||||
|
||||
# Treat warnings as errors
|
||||
function( set_warning_as_error )
|
||||
message( STATUS "[${PROJECT_NAME}] Treating warnings as errors")
|
||||
|
||||
if ( CMAKE_VERSION VERSION_GREATER_EQUAL "3.24" )
|
||||
set_target_properties( ${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
COMPILE_WARNING_AS_ERROR ON
|
||||
)
|
||||
else()
|
||||
# This will do nothing on compilers other than MSVC, Clang, Apple Clang, and GNU compilers.
|
||||
target_compile_options( ${PROJECT_NAME}
|
||||
PRIVATE
|
||||
$<${compiler_is_msvc}:
|
||||
/WX
|
||||
>
|
||||
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:
|
||||
-Werror
|
||||
>
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if ( ${PROJECT_NAME_UPPERCASE}_WARNING_AS_ERROR )
|
||||
set_warning_as_error()
|
||||
endif()
|
||||
@@ -1,11 +1,13 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# Copyright 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
# Generate the export header file for E57Format
|
||||
|
||||
include( GenerateExportHeader )
|
||||
|
||||
set( comment "// NOTE: This is a generated file. Any changes will be overwritten." )
|
||||
set( comment "\r
|
||||
// NOTE: This is a generated file. Any changes will be overwritten."
|
||||
)
|
||||
|
||||
generate_export_header( E57Format
|
||||
EXPORT_FILE_NAME E57Export.h
|
||||
122
src/3rdParty/libE57Format/cmake/GitInfo.cmake
vendored
Normal file
122
src/3rdParty/libE57Format/cmake/GitInfo.cmake
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
# ---------------------------------------------------------------------------- #
|
||||
#
|
||||
# Copyright (c) 2020 C++ Modern Framework
|
||||
#
|
||||
# https://github.com/cppmf/GitInfo.cmake
|
||||
#
|
||||
# ---------------------------------------------------------------------------- #
|
||||
|
||||
# Modified June 2024 - Andy Maloney <asmaloney@gmail.com>
|
||||
# - remove some vars we aren't using
|
||||
# - fix spelling/grammar
|
||||
|
||||
# ---------------------------------------------------------------------------- #
|
||||
#
|
||||
# Following variables will be set when calling GitInfo
|
||||
#
|
||||
# GIT_DIR: path to the project .git directory
|
||||
# GIT_IS_DIRTY: whether or not the working tree is dirty
|
||||
# GIT_HEAD_BRANCH : name of the branch associated to HEAD
|
||||
# GIT_REVISION_HASH: current HEAD sha hash
|
||||
# GIT_REVISION: short version of GIT_REVISION_HASH
|
||||
# GIT_REVISION_NAME: name associated to GIT_REVISION_HASH
|
||||
# GIT_REMOTE_ORIGIN_URL : origin remote url
|
||||
# GIT_LATEST_TAG_LONG : most recent tag of the current branch
|
||||
# GIT_LATEST_TAG : most recent tagname of the current branch
|
||||
#
|
||||
# ---------------------------------------------------------------------------- #
|
||||
|
||||
# This is the main function to call in project CMakeLists.txt
|
||||
# source should point to the root project directory
|
||||
function(GitInfo source)
|
||||
|
||||
# Check is source is a valid path
|
||||
if(NOT EXISTS ${source})
|
||||
message(FATAL_ERROR "'${source}' is not a valid path")
|
||||
endif()
|
||||
|
||||
# Define the possible location of the .git directory
|
||||
set(GIT_DIR "${source}/.git")
|
||||
|
||||
# Check if .git folder exist
|
||||
if(EXISTS ${GIT_DIR})
|
||||
|
||||
#
|
||||
set(GIT_DIR "${GIT_DIR}" CACHE PATH "Project .git directory")
|
||||
|
||||
# Check if git is installed
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
if(NOT GIT_FOUND)
|
||||
message(AUTHOR_WARNING "Git not found, cannot get git information")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# name of the branch associated to HEAD
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
|
||||
WORKING_DIRECTORY ${source}
|
||||
OUTPUT_VARIABLE GIT_HEAD_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(GIT_HEAD_BRANCH "${GIT_HEAD_BRANCH}" CACHE INTERNAL "name of the branch associated to HEAD")
|
||||
|
||||
# git revision full hash
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} show -s "--format=%H" HEAD
|
||||
WORKING_DIRECTORY ${source}
|
||||
OUTPUT_VARIABLE GIT_REVISION_HASH OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(GIT_REVISION_HASH "${GIT_REVISION_HASH}" CACHE INTERNAL "git revision full hash")
|
||||
|
||||
# short version of git revision
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} show -s "--format=%h" HEAD
|
||||
WORKING_DIRECTORY ${source}
|
||||
OUTPUT_VARIABLE GIT_REVISION OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(GIT_REVISION "${GIT_REVISION}" CACHE INTERNAL "short version of git revision")
|
||||
|
||||
# short version of git revision name
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} show -s "--format=%s" HEAD
|
||||
WORKING_DIRECTORY ${source}
|
||||
OUTPUT_VARIABLE GIT_REVISION_NAME OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(GIT_REVISION_NAME "${GIT_REVISION_NAME}" CACHE INTERNAL "short version of git revision name")
|
||||
|
||||
# origin remote url
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} config --get remote.origin.url
|
||||
WORKING_DIRECTORY ${source}
|
||||
OUTPUT_VARIABLE GIT_REMOTE_ORIGIN_URL OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(GIT_REMOTE_ORIGIN_URL "${GIT_REMOTE_ORIGIN_URL}" CACHE INTERNAL "git origin remote url")
|
||||
|
||||
# most recent tag of the current branch
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 HEAD
|
||||
WORKING_DIRECTORY ${source}
|
||||
OUTPUT_VARIABLE GIT_LATEST_TAG_LONG OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(GIT_LATEST_TAG_LONG "${GIT_LATEST_TAG_LONG}" CACHE INTERNAL "git most recent tag of the current branch")
|
||||
|
||||
# most recent tagname of the current branch
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags HEAD
|
||||
WORKING_DIRECTORY ${source}
|
||||
OUTPUT_VARIABLE GIT_LATEST_TAG OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(GIT_LATEST_TAG "${GIT_LATEST_TAG}" CACHE INTERNAL "git most recent tagname of the current branch")
|
||||
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
# Report git information
|
||||
function(GitInfoReport)
|
||||
message(STATUS "")
|
||||
message(STATUS "----------------------------------------------------")
|
||||
message(STATUS " GitInfo.cmake")
|
||||
message(STATUS "")
|
||||
message(STATUS "GIT_DIR : ${GIT_DIR}")
|
||||
message(STATUS "")
|
||||
message(STATUS "GIT_HEAD_BRANCH : ${GIT_HEAD_BRANCH}")
|
||||
message(STATUS "GIT_REVISION : ${GIT_REVISION}")
|
||||
message(STATUS "GIT_REVISION_HASH : ${GIT_REVISION_HASH}")
|
||||
message(STATUS "GIT_REVISION_NAME : ${GIT_REVISION_NAME}")
|
||||
message(STATUS "")
|
||||
message(STATUS "GIT_REMOTE_ORIGIN_URL : ${GIT_REMOTE_ORIGIN_URL}")
|
||||
message(STATUS "GIT_LATEST_TAG_LONG : ${GIT_LATEST_TAG_LONG}")
|
||||
message(STATUS "GIT_LATEST_TAG : ${GIT_LATEST_TAG}")
|
||||
message(STATUS "")
|
||||
message(STATUS "----------------------------------------------------")
|
||||
message(STATUS "")
|
||||
endfunction()
|
||||
22
src/3rdParty/libE57Format/cmake/GitUpdate.cmake
vendored
Normal file
22
src/3rdParty/libE57Format/cmake/GitUpdate.cmake
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
find_package( Git QUIET )
|
||||
|
||||
if ( GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git" )
|
||||
# Update submodules as needed
|
||||
option( E57_GIT_SUBMODULE_UPDATE "Check submodules and update during build" ON )
|
||||
|
||||
if ( E57_GIT_SUBMODULE_UPDATE )
|
||||
message( STATUS "Submodule update using git (${GIT_EXECUTABLE})" )
|
||||
message( STATUS "Submodule update directory: ${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
|
||||
execute_process( COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE GIT_SUBMOD_RESULT
|
||||
ERROR_VARIABLE GIT_SUBMOD_RESULT)
|
||||
|
||||
if ( GIT_SUBMOD_RESULT EQUAL "0" )
|
||||
message( STATUS "Submodule update complete" )
|
||||
else()
|
||||
message( FATAL_ERROR "Submodule update failed with ${GIT_SUBMOD_RESULT}, please checkout submodules" )
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,19 +0,0 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Copyright 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
find_program( E57_CLANG_FORMAT_EXE NAMES clang-format )
|
||||
|
||||
if ( E57_CLANG_FORMAT_EXE )
|
||||
get_target_property( e57_sources ${PROJECT_NAME} SOURCES )
|
||||
|
||||
# Remove some files from the list
|
||||
list( FILTER e57_sources EXCLUDE REGEX ".*/E57Export.h" )
|
||||
list( FILTER e57_sources EXCLUDE REGEX ".*/extern/.*" )
|
||||
|
||||
add_custom_target( format
|
||||
COMMAND clang-format --style=file -i ${e57_sources}
|
||||
COMMENT "Running clang-format..."
|
||||
COMMAND_EXPAND_LISTS
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file defines the variables
|
||||
# ${PROJECT_NAME}_BUILD_TAG
|
||||
|
||||
# calculate the tag
|
||||
set(T_ ${CMAKE_SYSTEM_PROCESSOR})
|
||||
if (CMAKE_CL_64)
|
||||
set(T_ ${T_}_64)
|
||||
endif (CMAKE_CL_64)
|
||||
string(TOLOWER ${CMAKE_SYSTEM_NAME} T1_)
|
||||
set(T_ ${T_}-${T1_})
|
||||
if (MSVC90)
|
||||
set(T1_ "-vc90")
|
||||
elseif (MSVC10)
|
||||
set(T1_ "-vc100")
|
||||
elseif (MSVC80)
|
||||
set(T1_ "-vc80")
|
||||
elseif (MSVC71)
|
||||
set(T1_ "-vc711")
|
||||
elseif (MSVC70)
|
||||
set(T1_ "-vc7")
|
||||
elseif (MINGW)
|
||||
set(T1_ "-mgw")
|
||||
exec_program(${CMAKE_CXX_COMPILER}
|
||||
ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion
|
||||
OUTPUT_VARIABLE T2_
|
||||
)
|
||||
string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" T2_ ${T2_})
|
||||
set(T1_ ${T1_}${T2_})
|
||||
elseif (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(T1_ "-gcc")
|
||||
exec_program(${CMAKE_CXX_COMPILER}
|
||||
ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion
|
||||
OUTPUT_VARIABLE T2_
|
||||
)
|
||||
string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" T2_ ${T2_})
|
||||
set(T1_ ${T1_}${T2_})
|
||||
else()
|
||||
set(T1_)
|
||||
endif()
|
||||
set(T_ ${T_}${T1_})
|
||||
set(${PROJECT_NAME}_BUILD_TAG ${T_})
|
||||
93
src/3rdParty/libE57Format/cmake/Sanitizers.cmake
vendored
Normal file
93
src/3rdParty/libE57Format/cmake/Sanitizers.cmake
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# Copyright 2023 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
# Note: In theory address sanitization should work on MSVC, but I could not get it working.
|
||||
# If you know how to fix it, please submit a PR:
|
||||
# https://github.com/asmaloney/libE57Format/pulls
|
||||
|
||||
string( TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPERCASE )
|
||||
|
||||
set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
|
||||
set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" )
|
||||
set( compiler_is_msvc "$<CXX_COMPILER_ID:MSVC>" )
|
||||
set( compiler_is_not_msvc "$<NOT:${compiler_is_msvc}>" )
|
||||
|
||||
if ( NOT MSVC )
|
||||
option( ${PROJECT_NAME_UPPERCASE}_SANITIZE_ALL "Enable all sanitizers if available." OFF )
|
||||
option( ${PROJECT_NAME_UPPERCASE}_SANITIZE_ADDRESS "Enable address sanitizer (ASan) if available." OFF )
|
||||
option( ${PROJECT_NAME_UPPERCASE}_SANITIZE_UNDEFINED "Enable memory sanitizer (UBSan) if available." OFF )
|
||||
endif()
|
||||
|
||||
function( enable_address_sanitizer target )
|
||||
message( STATUS "[${target}] Enabling address sanitizer (ASan)" )
|
||||
|
||||
target_compile_options( ${target}
|
||||
PRIVATE
|
||||
$<${compiler_is_not_msvc}:
|
||||
-fno-omit-frame-pointer
|
||||
-fsanitize=address
|
||||
>
|
||||
|
||||
$<${compiler_is_msvc}:
|
||||
/fsanitize=address
|
||||
/INCREMENTAL:NO
|
||||
/Zi
|
||||
>
|
||||
)
|
||||
target_link_options( ${target}
|
||||
PUBLIC
|
||||
$<${compiler_is_not_msvc}:
|
||||
-fno-omit-frame-pointer
|
||||
-fsanitize=address
|
||||
>
|
||||
|
||||
$<${compiler_is_msvc}:
|
||||
/DEBUG
|
||||
/INCREMENTAL:NO
|
||||
>
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function( enable_undefined_sanitizer target )
|
||||
if ( MSVC )
|
||||
message( WARNING "[${target}] Undefined behaviour sanitizer (UBSan) not available for MSVC" )
|
||||
return()
|
||||
endif()
|
||||
|
||||
message( STATUS "[${target}] Enabling undefined behaviour sanitizer (UBSan)" )
|
||||
|
||||
target_compile_options( ${target}
|
||||
PRIVATE
|
||||
-fsanitize=undefined
|
||||
)
|
||||
target_link_options( ${target}
|
||||
PUBLIC
|
||||
-fsanitize=undefined
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function( enable_all_sanitizers target )
|
||||
if ( MSVC )
|
||||
return()
|
||||
endif()
|
||||
|
||||
unset( ${PROJECT_NAME_UPPERCASE}_SANITIZE_ADDRESS CACHE )
|
||||
unset( ${PROJECT_NAME_UPPERCASE}_SANITIZE_UNDEFINED CACHE )
|
||||
|
||||
enable_address_sanitizer( ${target} )
|
||||
enable_undefined_sanitizer( ${target} )
|
||||
endfunction()
|
||||
|
||||
if ( NOT MSVC )
|
||||
if ( ${PROJECT_NAME_UPPERCASE}_SANITIZE_ALL )
|
||||
enable_all_sanitizers( ${PROJECT_NAME} )
|
||||
else()
|
||||
if ( ${PROJECT_NAME_UPPERCASE}_SANITIZE_ADDRESS )
|
||||
enable_address_sanitizer( ${PROJECT_NAME} )
|
||||
endif()
|
||||
|
||||
if ( ${PROJECT_NAME_UPPERCASE}_SANITIZE_UNDEFINED )
|
||||
enable_undefined_sanitizer( ${PROJECT_NAME} )
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
39
src/3rdParty/libE57Format/cmake/Tags.cmake
vendored
Normal file
39
src/3rdParty/libE57Format/cmake/Tags.cmake
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# This file defines the variables
|
||||
# ${PROJECT_NAME}_BUILD_TAG
|
||||
|
||||
set( T_ ${CMAKE_SYSTEM_PROCESSOR} )
|
||||
|
||||
string( TOLOWER ${CMAKE_SYSTEM_NAME} T1_ )
|
||||
|
||||
function( add_compiler_version )
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} -dumpversion
|
||||
OUTPUT_VARIABLE T2_
|
||||
)
|
||||
string( REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" T2_ ${T2_} )
|
||||
string( STRIP ${T2_} T2_ )
|
||||
set( T1_ ${T1_}${T2_} PARENT_SCOPE )
|
||||
endfunction()
|
||||
|
||||
# default to just the CMake compiler ID
|
||||
set( T1_ ${CMAKE_CXX_COMPILER_ID} )
|
||||
|
||||
# special cases to add versions and other info
|
||||
if ( MSVC )
|
||||
if ( CMAKE_CL_64 )
|
||||
set( T_ ${T_}_64 )
|
||||
endif()
|
||||
|
||||
set( T1_ "vc${MSVC_VERSION}" )
|
||||
elseif ( MINGW )
|
||||
set( T1_ "MinGW" )
|
||||
add_compiler_version()
|
||||
elseif ( CMAKE_CXX_COMPILER_ID STREQUAL "GNU" )
|
||||
set( T1_ "gcc" )
|
||||
add_compiler_version()
|
||||
elseif ( CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compiler_version()
|
||||
endif()
|
||||
|
||||
set( T_ ${T_}-${T1_} )
|
||||
set( ${PROJECT_NAME}_BUILD_TAG ${T_} )
|
||||
15
src/3rdParty/libE57Format/cmake/ccache.cmake
vendored
Normal file
15
src/3rdParty/libE57Format/cmake/ccache.cmake
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# Copyright 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
# See: https://crascit.com/2016/04/09/using-ccache-with-cmake/
|
||||
find_program( CCACHE_PROGRAM ccache )
|
||||
|
||||
if ( CCACHE_PROGRAM )
|
||||
message( STATUS "[${PROJECT_NAME}] Using ccache: ${CCACHE_PROGRAM}" )
|
||||
|
||||
set_target_properties( ${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}"
|
||||
C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}"
|
||||
)
|
||||
endif()
|
||||
@@ -1,14 +1,20 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# Copyright © Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
# CRCpp from here: https://github.com/d-bahr/CRCpp
|
||||
|
||||
target_compile_definitions( ${PROJECT_NAME}
|
||||
PRIVATE
|
||||
CRCPP_USE_CPP11
|
||||
CRCPP_BRANCHLESS
|
||||
)
|
||||
|
||||
target_sources( ${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/inc/CRC.h
|
||||
inc/CRC.h
|
||||
)
|
||||
|
||||
target_include_directories( ${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/inc
|
||||
inc
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
CRC++
|
||||
Copyright (c) 2016, Daniel Bahr
|
||||
Copyright (c) 2022, Daniel Bahr
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
69
src/3rdParty/libE57Format/extern/CRCpp/README.md
vendored
69
src/3rdParty/libE57Format/extern/CRCpp/README.md
vendored
@@ -82,7 +82,24 @@ int main(int argc, char ** argv)
|
||||
|
||||
This will return the same CRC as the first example.
|
||||
|
||||
Both of the above examples compute a CRC bit-by-bit. However, CRC++ also supports lookup tables, as the following example demonstrates:
|
||||
If you need to compute a CRC on an input that is not a multiple of `CHAR_BIT` (usually 8 bits), use the `CalculateBits()` function instead:
|
||||
|
||||
```cpp
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
const unsigned char data[] = { 0x98, 0x76, 0x54, 0x32, 0x10 };
|
||||
|
||||
// Second argument is the number of bits. The input data must
|
||||
// be a whole number of bytes. Pad any used bits with zeros.
|
||||
std::uint32_t crc = CRC::CalculateBits(data, 37, CRC::CRC_32());
|
||||
|
||||
std::cout << std::hex << crc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
The above examples compute a CRC bit-by-bit. However, CRC++ also supports lookup tables, as the following example demonstrates:
|
||||
|
||||
```cpp
|
||||
int main(int argc, char ** argv)
|
||||
@@ -149,6 +166,56 @@ Define to enables C++11 features (move semantics, constexpr, static_assert, etc.
|
||||
* `#define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS`
|
||||
Define to include definitions for little-used CRCs. Not defined by default.
|
||||
|
||||
### Build
|
||||
|
||||
CRC does not require a build for basic usage; simply include the header file in your project.
|
||||
|
||||
Unit tests and documentation can be built manually with the project files provided or automatically with CMake.
|
||||
|
||||
To build documentation manually:
|
||||
```bash
|
||||
cd doxygen
|
||||
doxygen Doxyfile.dox
|
||||
```
|
||||
|
||||
To build unit tests manually via Make:
|
||||
```bash
|
||||
# Build
|
||||
cd test/prj/gcc
|
||||
make [debug|release]
|
||||
# Run unit tests
|
||||
bin/unittest
|
||||
```
|
||||
|
||||
Project files and solutions for Visual Studio 2015, 2017 and 2022 are provided in `test/prj`. Simply open the solution file and run the project; no additional configuration should be necessary.
|
||||
|
||||
CMake can also be used to build the documentation and unit tests. An out-of-source build is recommended. In this example, we will do an out-of-source build in the `build` directory:
|
||||
```bash
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake .. [-DBUILD_DOC=ON]
|
||||
# Build and run unit tests
|
||||
make tests
|
||||
# Build documentation
|
||||
make doxygen
|
||||
# Install header file
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Unit tests are built by default. Enable the `BUILD_DOC` CMake flag to also build documentation (requires [Doxygen](https://www.doxygen.nl/index.html)).
|
||||
|
||||
### Documentation
|
||||
|
||||
https://d-bahr.github.io/CRCpp/
|
||||
|
||||
### License
|
||||
|
||||
CRC++ is free to use and provided under a BSD license.
|
||||
|
||||
### References
|
||||
|
||||
Catalog of CRCs: https://reveng.sourceforge.io/crc-catalogue/
|
||||
|
||||
5G-NR Specification 3GPP TS 38.212: https://www.etsi.org/deliver/etsi_ts/138200_138299/138212/15.03.00_60/ts_138212v150300p.pdf
|
||||
|
||||
USB 2.0 Specification: https://www.usb.org/document-library/usb-20-specification
|
||||
|
||||
531
src/3rdParty/libE57Format/extern/CRCpp/inc/CRC.h
vendored
531
src/3rdParty/libE57Format/extern/CRCpp/inc/CRC.h
vendored
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
@file CRC.h
|
||||
@author Daniel Bahr
|
||||
@version 0.2.0.6
|
||||
@version 1.2.0.0
|
||||
@copyright
|
||||
@parblock
|
||||
CRC++
|
||||
Copyright (c) 2016, Daniel Bahr
|
||||
Copyright (c) 2022, Daniel Bahr
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -52,7 +52,7 @@
|
||||
multiplication in the bit-by-bit calculation instead of a small conditional. The branchless implementation
|
||||
may be faster on processor architectures which support single-instruction integer multiplication.
|
||||
#define CRCPP_USE_CPP11 - Define to enables C++11 features (move semantics, constexpr, static_assert, etc.).
|
||||
#define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS - Define to include definitions for little-used CRCs.
|
||||
#define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS - Define to include definitions for little-used CRCs.
|
||||
*/
|
||||
|
||||
#ifndef CRCPP_CRC_H_
|
||||
@@ -127,6 +127,12 @@
|
||||
# define crcpp_constexpr const
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER)
|
||||
/* Disable warning C4127: conditional expression is constant. */
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
#ifdef CRCPP_USE_NAMESPACE
|
||||
namespace CRCPP
|
||||
{
|
||||
@@ -202,6 +208,18 @@ public:
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
static CRCType Calculate(const void * data, crcpp_size size, const Table<CRCType, CRCWidth> & lookupTable, CRCType crc);
|
||||
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
static CRCType CalculateBits(const void * data, crcpp_size size, const Parameters<CRCType, CRCWidth> & parameters);
|
||||
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
static CRCType CalculateBits(const void * data, crcpp_size size, const Parameters<CRCType, CRCWidth> & parameters, CRCType crc);
|
||||
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
static CRCType CalculateBits(const void * data, crcpp_size size, const Table<CRCType, CRCWidth> & lookupTable);
|
||||
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
static CRCType CalculateBits(const void * data, crcpp_size size, const Table<CRCType, CRCWidth> & lookupTable, CRCType crc);
|
||||
|
||||
// Common CRCs up to 64 bits.
|
||||
// Note: Check values are the computed CRCs when given an ASCII input of "123456789" (without null terminator)
|
||||
#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS
|
||||
@@ -212,16 +230,20 @@ public:
|
||||
static const Parameters< crcpp_uint8, 6> & CRC_6_CDMA2000A();
|
||||
static const Parameters< crcpp_uint8, 6> & CRC_6_CDMA2000B();
|
||||
static const Parameters< crcpp_uint8, 6> & CRC_6_ITU();
|
||||
static const Parameters< crcpp_uint8, 6> & CRC_6_NR();
|
||||
static const Parameters< crcpp_uint8, 7> & CRC_7();
|
||||
#endif
|
||||
static const Parameters< crcpp_uint8, 8> & CRC_8();
|
||||
#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS
|
||||
static const Parameters< crcpp_uint8, 8> & CRC_8_EBU();
|
||||
static const Parameters< crcpp_uint8, 8> & CRC_8_HDLC();
|
||||
static const Parameters< crcpp_uint8, 8> & CRC_8_MAXIM();
|
||||
static const Parameters< crcpp_uint8, 8> & CRC_8_WCDMA();
|
||||
static const Parameters< crcpp_uint8, 8> & CRC_8_LTE();
|
||||
static const Parameters<crcpp_uint16, 10> & CRC_10();
|
||||
static const Parameters<crcpp_uint16, 10> & CRC_10_CDMA2000();
|
||||
static const Parameters<crcpp_uint16, 11> & CRC_11();
|
||||
static const Parameters<crcpp_uint16, 11> & CRC_11_NR();
|
||||
static const Parameters<crcpp_uint16, 12> & CRC_12_CDMA2000();
|
||||
static const Parameters<crcpp_uint16, 12> & CRC_12_DECT();
|
||||
static const Parameters<crcpp_uint16, 12> & CRC_12_UMTS();
|
||||
@@ -232,8 +254,10 @@ public:
|
||||
static const Parameters<crcpp_uint16, 16> & CRC_16_ARC();
|
||||
static const Parameters<crcpp_uint16, 16> & CRC_16_BUYPASS();
|
||||
static const Parameters<crcpp_uint16, 16> & CRC_16_CCITTFALSE();
|
||||
static const Parameters<crcpp_uint16, 16> & CRC_16_MCRF4XX();
|
||||
#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS
|
||||
static const Parameters<crcpp_uint16, 16> & CRC_16_CDMA2000();
|
||||
static const Parameters<crcpp_uint16, 16> & CRC_16_CMS();
|
||||
static const Parameters<crcpp_uint16, 16> & CRC_16_DECTR();
|
||||
static const Parameters<crcpp_uint16, 16> & CRC_16_DECTX();
|
||||
static const Parameters<crcpp_uint16, 16> & CRC_16_DNP();
|
||||
@@ -254,6 +278,9 @@ public:
|
||||
static const Parameters<crcpp_uint32, 24> & CRC_24();
|
||||
static const Parameters<crcpp_uint32, 24> & CRC_24_FLEXRAYA();
|
||||
static const Parameters<crcpp_uint32, 24> & CRC_24_FLEXRAYB();
|
||||
static const Parameters<crcpp_uint32, 24> & CRC_24_LTEA();
|
||||
static const Parameters<crcpp_uint32, 24> & CRC_24_LTEB();
|
||||
static const Parameters<crcpp_uint32, 24> & CRC_24_NRC();
|
||||
static const Parameters<crcpp_uint32, 30> & CRC_30();
|
||||
#endif
|
||||
static const Parameters<crcpp_uint32, 32> & CRC_32();
|
||||
@@ -299,8 +326,8 @@ private:
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
static CRCType CalculateRemainder(const void * data, crcpp_size size, const Table<CRCType, CRCWidth> & lookupTable, CRCType remainder);
|
||||
|
||||
template <typename IntegerType>
|
||||
static crcpp_constexpr IntegerType BoundedConstexprValue(IntegerType x);
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
static CRCType CalculateRemainderBits(unsigned char byte, crcpp_size numBits, const Parameters<CRCType, CRCWidth> & parameters, CRCType remainder);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -320,13 +347,13 @@ inline CRC::Table<CRCType, CRCWidth> CRC::Parameters<CRCType, CRCWidth>::MakeTab
|
||||
|
||||
/**
|
||||
@brief Constructs a CRC table from a set of CRC parameters
|
||||
@param[in] parameters CRC parameters
|
||||
@param[in] params CRC parameters
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@tparam CRCWidth Number of bits in the CRC
|
||||
*/
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
inline CRC::Table<CRCType, CRCWidth>::Table(const Parameters<CRCType, CRCWidth> & parameters) :
|
||||
parameters(parameters)
|
||||
inline CRC::Table<CRCType, CRCWidth>::Table(const Parameters<CRCType, CRCWidth> & params) :
|
||||
parameters(params)
|
||||
{
|
||||
InitTable();
|
||||
}
|
||||
@@ -334,13 +361,13 @@ inline CRC::Table<CRCType, CRCWidth>::Table(const Parameters<CRCType, CRCWidth>
|
||||
#ifdef CRCPP_USE_CPP11
|
||||
/**
|
||||
@brief Constructs a CRC table from a set of CRC parameters
|
||||
@param[in] parameters CRC parameters
|
||||
@param[in] params CRC parameters
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@tparam CRCWidth Number of bits in the CRC
|
||||
*/
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
inline CRC::Table<CRCType, CRCWidth>::Table(Parameters<CRCType, CRCWidth> && parameters) :
|
||||
parameters(::std::move(parameters))
|
||||
inline CRC::Table<CRCType, CRCWidth>::Table(Parameters<CRCType, CRCWidth> && params) :
|
||||
parameters(::std::move(params))
|
||||
{
|
||||
InitTable();
|
||||
}
|
||||
@@ -395,7 +422,8 @@ inline void CRC::Table<CRCType, CRCWidth>::InitTable()
|
||||
static crcpp_constexpr CRCType BIT_MASK((CRCType(1) << (CRCWidth - CRCType(1))) |
|
||||
((CRCType(1) << (CRCWidth - CRCType(1))) - CRCType(1)));
|
||||
|
||||
static crcpp_constexpr CRCType SHIFT(CRC::BoundedConstexprValue(CHAR_BIT - CRCWidth));
|
||||
// The conditional expression is used to avoid a -Wshift-count-overflow warning.
|
||||
static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast<CRCType>(CHAR_BIT - CRCWidth) : 0);
|
||||
|
||||
CRCType crc;
|
||||
unsigned char byte = 0;
|
||||
@@ -414,7 +442,7 @@ inline void CRC::Table<CRCType, CRCWidth>::InitTable()
|
||||
{
|
||||
// Undo the special operation at the end of the CalculateRemainder()
|
||||
// function for non-reflected CRCs < CHAR_BIT.
|
||||
crc <<= SHIFT;
|
||||
crc = static_cast<CRCType>(crc << SHIFT);
|
||||
}
|
||||
|
||||
table[byte] = crc;
|
||||
@@ -425,7 +453,7 @@ inline void CRC::Table<CRCType, CRCWidth>::InitTable()
|
||||
/**
|
||||
@brief Computes a CRC.
|
||||
@param[in] data Data over which CRC will be computed
|
||||
@param[in] size Size of the data
|
||||
@param[in] size Size of the data, in bytes
|
||||
@param[in] parameters CRC parameters
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@tparam CRCWidth Number of bits in the CRC
|
||||
@@ -444,7 +472,7 @@ inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Paramete
|
||||
@brief Appends additional data to a previous CRC calculation.
|
||||
@note This function can be used to compute multi-part CRCs.
|
||||
@param[in] data Data over which CRC will be computed
|
||||
@param[in] size Size of the data
|
||||
@param[in] size Size of the data, in bytes
|
||||
@param[in] parameters CRC parameters
|
||||
@param[in] crc CRC from a previous calculation
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@@ -466,7 +494,7 @@ inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Paramete
|
||||
/**
|
||||
@brief Computes a CRC via a lookup table.
|
||||
@param[in] data Data over which CRC will be computed
|
||||
@param[in] size Size of the data
|
||||
@param[in] size Size of the data, in bytes
|
||||
@param[in] lookupTable CRC lookup table
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@tparam CRCWidth Number of bits in the CRC
|
||||
@@ -488,7 +516,7 @@ inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Table<CR
|
||||
@brief Appends additional data to a previous CRC calculation using a lookup table.
|
||||
@note This function can be used to compute multi-part CRCs.
|
||||
@param[in] data Data over which CRC will be computed
|
||||
@param[in] size Size of the data
|
||||
@param[in] size Size of the data, in bytes
|
||||
@param[in] lookupTable CRC lookup table
|
||||
@param[in] crc CRC from a previous calculation
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@@ -509,6 +537,149 @@ inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Table<CR
|
||||
return Finalize<CRCType, CRCWidth>(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Computes a CRC.
|
||||
@param[in] data Data over which CRC will be computed
|
||||
@param[in] size Size of the data, in bits
|
||||
@param[in] parameters CRC parameters
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@tparam CRCWidth Number of bits in the CRC
|
||||
@return CRC
|
||||
*/
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
inline CRCType CRC::CalculateBits(const void * data, crcpp_size size, const Parameters<CRCType, CRCWidth> & parameters)
|
||||
{
|
||||
CRCType remainder = parameters.initialValue;
|
||||
|
||||
// Calculate the remainder on a whole number of bytes first, then call
|
||||
// a special-case function for the remaining bits.
|
||||
crcpp_size wholeNumberOfBytes = size / CHAR_BIT;
|
||||
if (wholeNumberOfBytes > 0)
|
||||
{
|
||||
remainder = CalculateRemainder(data, wholeNumberOfBytes, parameters, remainder);
|
||||
}
|
||||
|
||||
crcpp_size remainingNumberOfBits = size % CHAR_BIT;
|
||||
if (remainingNumberOfBits != 0)
|
||||
{
|
||||
unsigned char lastByte = *(reinterpret_cast<const unsigned char *>(data) + wholeNumberOfBytes);
|
||||
remainder = CalculateRemainderBits(lastByte, remainingNumberOfBits, parameters, remainder);
|
||||
}
|
||||
|
||||
// No need to mask the remainder here; the mask will be applied in the Finalize() function.
|
||||
|
||||
return Finalize<CRCType, CRCWidth>(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput);
|
||||
}
|
||||
/**
|
||||
@brief Appends additional data to a previous CRC calculation.
|
||||
@note This function can be used to compute multi-part CRCs.
|
||||
@param[in] data Data over which CRC will be computed
|
||||
@param[in] size Size of the data, in bits
|
||||
@param[in] parameters CRC parameters
|
||||
@param[in] crc CRC from a previous calculation
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@tparam CRCWidth Number of bits in the CRC
|
||||
@return CRC
|
||||
*/
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
inline CRCType CRC::CalculateBits(const void * data, crcpp_size size, const Parameters<CRCType, CRCWidth> & parameters, CRCType crc)
|
||||
{
|
||||
CRCType remainder = UndoFinalize<CRCType, CRCWidth>(crc, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput);
|
||||
|
||||
// Calculate the remainder on a whole number of bytes first, then call
|
||||
// a special-case function for the remaining bits.
|
||||
crcpp_size wholeNumberOfBytes = size / CHAR_BIT;
|
||||
if (wholeNumberOfBytes > 0)
|
||||
{
|
||||
remainder = CalculateRemainder(data, wholeNumberOfBytes, parameters, parameters.initialValue);
|
||||
}
|
||||
|
||||
crcpp_size remainingNumberOfBits = size % CHAR_BIT;
|
||||
if (remainingNumberOfBits != 0)
|
||||
{
|
||||
unsigned char lastByte = *(reinterpret_cast<const unsigned char *>(data) + wholeNumberOfBytes);
|
||||
remainder = CalculateRemainderBits(lastByte, remainingNumberOfBits, parameters, remainder);
|
||||
}
|
||||
|
||||
// No need to mask the remainder here; the mask will be applied in the Finalize() function.
|
||||
|
||||
return Finalize<CRCType, CRCWidth>(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Computes a CRC via a lookup table.
|
||||
@param[in] data Data over which CRC will be computed
|
||||
@param[in] size Size of the data, in bits
|
||||
@param[in] lookupTable CRC lookup table
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@tparam CRCWidth Number of bits in the CRC
|
||||
@return CRC
|
||||
*/
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
inline CRCType CRC::CalculateBits(const void * data, crcpp_size size, const Table<CRCType, CRCWidth> & lookupTable)
|
||||
{
|
||||
const Parameters<CRCType, CRCWidth> & parameters = lookupTable.GetParameters();
|
||||
|
||||
CRCType remainder = parameters.initialValue;
|
||||
|
||||
// Calculate the remainder on a whole number of bytes first, then call
|
||||
// a special-case function for the remaining bits.
|
||||
crcpp_size wholeNumberOfBytes = size / CHAR_BIT;
|
||||
if (wholeNumberOfBytes > 0)
|
||||
{
|
||||
remainder = CalculateRemainder(data, wholeNumberOfBytes, lookupTable, remainder);
|
||||
}
|
||||
|
||||
crcpp_size remainingNumberOfBits = size % CHAR_BIT;
|
||||
if (remainingNumberOfBits != 0)
|
||||
{
|
||||
unsigned char lastByte = *(reinterpret_cast<const unsigned char *>(data) + wholeNumberOfBytes);
|
||||
remainder = CalculateRemainderBits(lastByte, remainingNumberOfBits, parameters, remainder);
|
||||
}
|
||||
|
||||
// No need to mask the remainder here; the mask will be applied in the Finalize() function.
|
||||
|
||||
return Finalize<CRCType, CRCWidth>(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Appends additional data to a previous CRC calculation using a lookup table.
|
||||
@note This function can be used to compute multi-part CRCs.
|
||||
@param[in] data Data over which CRC will be computed
|
||||
@param[in] size Size of the data, in bits
|
||||
@param[in] lookupTable CRC lookup table
|
||||
@param[in] crc CRC from a previous calculation
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@tparam CRCWidth Number of bits in the CRC
|
||||
@return CRC
|
||||
*/
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
inline CRCType CRC::CalculateBits(const void * data, crcpp_size size, const Table<CRCType, CRCWidth> & lookupTable, CRCType crc)
|
||||
{
|
||||
const Parameters<CRCType, CRCWidth> & parameters = lookupTable.GetParameters();
|
||||
|
||||
CRCType remainder = UndoFinalize<CRCType, CRCWidth>(crc, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput);
|
||||
|
||||
// Calculate the remainder on a whole number of bytes first, then call
|
||||
// a special-case function for the remaining bits.
|
||||
crcpp_size wholeNumberOfBytes = size / CHAR_BIT;
|
||||
if (wholeNumberOfBytes > 0)
|
||||
{
|
||||
remainder = CalculateRemainder(data, wholeNumberOfBytes, lookupTable, parameters.initialValue);
|
||||
}
|
||||
|
||||
crcpp_size remainingNumberOfBits = size % CHAR_BIT;
|
||||
if (remainingNumberOfBits > 0)
|
||||
{
|
||||
unsigned char lastByte = *(reinterpret_cast<const unsigned char *>(data) + wholeNumberOfBytes);
|
||||
remainder = CalculateRemainderBits(lastByte, remainingNumberOfBits, parameters, remainder);
|
||||
}
|
||||
|
||||
// No need to mask the remainder here; the mask will be applied in the Finalize() function.
|
||||
|
||||
return Finalize<CRCType, CRCWidth>(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Reflects (i.e. reverses the bits within) an integer value.
|
||||
@param[in] value Value to reflect
|
||||
@@ -523,8 +694,8 @@ inline IntegerType CRC::Reflect(IntegerType value, crcpp_uint16 numBits)
|
||||
|
||||
for (crcpp_uint16 i = 0; i < numBits; ++i)
|
||||
{
|
||||
reversedValue = (reversedValue << 1) | (value & 1);
|
||||
value >>= 1;
|
||||
reversedValue = static_cast<IntegerType>((reversedValue << 1) | (value & 1));
|
||||
value = static_cast<IntegerType>(value >> 1);
|
||||
}
|
||||
|
||||
return reversedValue;
|
||||
@@ -591,7 +762,7 @@ inline CRCType CRC::UndoFinalize(CRCType crc, CRCType finalXOR, bool reflectOutp
|
||||
/**
|
||||
@brief Computes a CRC remainder.
|
||||
@param[in] data Data over which the remainder will be computed
|
||||
@param[in] size Size of the data
|
||||
@param[in] size Size of the data, in bytes
|
||||
@param[in] parameters CRC parameters
|
||||
@param[in] remainder Running CRC remainder. Can be an initial value or the result of a previous CRC remainder calculation.
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@@ -620,7 +791,7 @@ inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const
|
||||
CRCType polynomial = CRC::Reflect(parameters.polynomial, CRCWidth);
|
||||
while (size--)
|
||||
{
|
||||
remainder ^= *current++;
|
||||
remainder = static_cast<CRCType>(remainder ^ *current++);
|
||||
|
||||
// An optimizing compiler might choose to unroll this loop.
|
||||
for (crcpp_size i = 0; i < CHAR_BIT; ++i)
|
||||
@@ -631,9 +802,9 @@ inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const
|
||||
// remainder = (remainder >> 1) ^ polynomial;
|
||||
// else
|
||||
// remainder >>= 1;
|
||||
remainder = (remainder >> 1) ^ ((remainder & 1) * polynomial);
|
||||
remainder = static_cast<CRCType>((remainder >> 1) ^ ((remainder & 1) * polynomial));
|
||||
#else
|
||||
remainder = (remainder & 1) ? ((remainder >> 1) ^ polynomial) : (remainder >> 1);
|
||||
remainder = static_cast<CRCType>((remainder & 1) ? ((remainder >> 1) ^ polynomial) : (remainder >> 1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -644,11 +815,12 @@ inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const
|
||||
#ifndef CRCPP_BRANCHLESS
|
||||
static crcpp_constexpr CRCType CRC_HIGHEST_BIT_MASK(CRCType(1) << CRC_WIDTH_MINUS_ONE);
|
||||
#endif
|
||||
static crcpp_constexpr CRCType SHIFT(BoundedConstexprValue(CRCWidth - CHAR_BIT));
|
||||
// The conditional expression is used to avoid a -Wshift-count-overflow warning.
|
||||
static crcpp_constexpr CRCType SHIFT((CRCWidth >= CHAR_BIT) ? static_cast<CRCType>(CRCWidth - CHAR_BIT) : 0);
|
||||
|
||||
while (size--)
|
||||
{
|
||||
remainder ^= (static_cast<CRCType>(*current++) << SHIFT);
|
||||
remainder = static_cast<CRCType>(remainder ^ (static_cast<CRCType>(*current++) << SHIFT));
|
||||
|
||||
// An optimizing compiler might choose to unroll this loop.
|
||||
for (crcpp_size i = 0; i < CHAR_BIT; ++i)
|
||||
@@ -659,9 +831,9 @@ inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const
|
||||
// remainder = (remainder << 1) ^ parameters.polynomial;
|
||||
// else
|
||||
// remainder <<= 1;
|
||||
remainder = (remainder << 1) ^ (((remainder >> CRC_WIDTH_MINUS_ONE) & 1) * parameters.polynomial);
|
||||
remainder = static_cast<CRCType>((remainder << 1) ^ (((remainder >> CRC_WIDTH_MINUS_ONE) & 1) * parameters.polynomial));
|
||||
#else
|
||||
remainder = (remainder & CRC_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ parameters.polynomial) : (remainder << 1);
|
||||
remainder = static_cast<CRCType>((remainder & CRC_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ parameters.polynomial) : (remainder << 1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -672,14 +844,15 @@ inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const
|
||||
#ifndef CRCPP_BRANCHLESS
|
||||
static crcpp_constexpr CRCType CHAR_BIT_HIGHEST_BIT_MASK(CRCType(1) << CHAR_BIT_MINUS_ONE);
|
||||
#endif
|
||||
static crcpp_constexpr CRCType SHIFT(BoundedConstexprValue(CHAR_BIT - CRCWidth));
|
||||
// The conditional expression is used to avoid a -Wshift-count-overflow warning.
|
||||
static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast<CRCType>(CHAR_BIT - CRCWidth) : 0);
|
||||
|
||||
CRCType polynomial = parameters.polynomial << SHIFT;
|
||||
remainder <<= SHIFT;
|
||||
CRCType polynomial = static_cast<CRCType>(parameters.polynomial << SHIFT);
|
||||
remainder = static_cast<CRCType>(remainder << SHIFT);
|
||||
|
||||
while (size--)
|
||||
{
|
||||
remainder ^= *current++;
|
||||
remainder = static_cast<CRCType>(remainder ^ *current++);
|
||||
|
||||
// An optimizing compiler might choose to unroll this loop.
|
||||
for (crcpp_size i = 0; i < CHAR_BIT; ++i)
|
||||
@@ -690,14 +863,14 @@ inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const
|
||||
// remainder = (remainder << 1) ^ polynomial;
|
||||
// else
|
||||
// remainder <<= 1;
|
||||
remainder = (remainder << 1) ^ (((remainder >> CHAR_BIT_MINUS_ONE) & 1) * polynomial);
|
||||
remainder = static_cast<CRCType>((remainder << 1) ^ (((remainder >> CHAR_BIT_MINUS_ONE) & 1) * polynomial));
|
||||
#else
|
||||
remainder = (remainder & CHAR_BIT_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ polynomial) : (remainder << 1);
|
||||
remainder = static_cast<CRCType>((remainder & CHAR_BIT_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ polynomial) : (remainder << 1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
remainder >>= SHIFT;
|
||||
remainder = static_cast<CRCType>(remainder >> SHIFT);
|
||||
}
|
||||
|
||||
return remainder;
|
||||
@@ -706,7 +879,7 @@ inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const
|
||||
/**
|
||||
@brief Computes a CRC remainder using lookup table.
|
||||
@param[in] data Data over which the remainder will be computed
|
||||
@param[in] size Size of the data
|
||||
@param[in] size Size of the data, in bytes
|
||||
@param[in] lookupTable CRC lookup table
|
||||
@param[in] remainder Running CRC remainder. Can be an initial value or the result of a previous CRC remainder calculation.
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@@ -722,37 +895,35 @@ inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const
|
||||
{
|
||||
while (size--)
|
||||
{
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WINCE)
|
||||
#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER)
|
||||
// Disable warning about data loss when doing (remainder >> CHAR_BIT) when
|
||||
// remainder is one byte long. The algorithm is still correct in this case,
|
||||
// though it's possible that one additional machine instruction will be executed.
|
||||
# if defined(_MSC_VER)
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable : 4333)
|
||||
# endif
|
||||
#endif
|
||||
remainder = (remainder >> CHAR_BIT) ^ lookupTable[static_cast<unsigned char>(remainder ^ *current++)];
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WINCE)
|
||||
# if defined(_MSC_VER)
|
||||
remainder = static_cast<CRCType>((remainder >> CHAR_BIT) ^ lookupTable[static_cast<unsigned char>(remainder ^ *current++)]);
|
||||
#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER)
|
||||
# pragma warning (pop)
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (CRCWidth >= CHAR_BIT)
|
||||
{
|
||||
static crcpp_constexpr CRCType SHIFT(BoundedConstexprValue(CRCWidth - CHAR_BIT));
|
||||
// The conditional expression is used to avoid a -Wshift-count-overflow warning.
|
||||
static crcpp_constexpr CRCType SHIFT((CRCWidth >= CHAR_BIT) ? static_cast<CRCType>(CRCWidth - CHAR_BIT) : 0);
|
||||
|
||||
while (size--)
|
||||
{
|
||||
remainder = (remainder << CHAR_BIT) ^ lookupTable[static_cast<unsigned char>((remainder >> SHIFT) ^ *current++)];
|
||||
remainder = static_cast<CRCType>((remainder << CHAR_BIT) ^ lookupTable[static_cast<unsigned char>((remainder >> SHIFT) ^ *current++)]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static crcpp_constexpr CRCType SHIFT(BoundedConstexprValue(CHAR_BIT - CRCWidth));
|
||||
// The conditional expression is used to avoid a -Wshift-count-overflow warning.
|
||||
static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast<CRCType>(CHAR_BIT - CRCWidth) : 0);
|
||||
|
||||
remainder <<= SHIFT;
|
||||
remainder = static_cast<CRCType>(remainder << SHIFT);
|
||||
|
||||
while (size--)
|
||||
{
|
||||
@@ -760,26 +931,94 @@ inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const
|
||||
remainder = lookupTable[static_cast<unsigned char>(remainder ^ *current++)];
|
||||
}
|
||||
|
||||
remainder >>= SHIFT;
|
||||
remainder = static_cast<CRCType>(remainder >> SHIFT);
|
||||
}
|
||||
|
||||
return remainder;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Function to force a compile-time expression to be >= 0.
|
||||
@note This function is used to avoid compiler warnings because all constexpr values are evaluated
|
||||
in a function even in a branch will never be executed. This also means we don't need pragmas
|
||||
to get rid of warnings, but it still can be computed at compile-time. Win-win!
|
||||
@param[in] x Compile-time expression to bound
|
||||
@tparam CRCType Integer type for storing the CRC result
|
||||
@tparam CRCWidth Number of bits in the CRC
|
||||
@return Non-negative compile-time expression
|
||||
*/
|
||||
template <typename IntegerType>
|
||||
inline crcpp_constexpr IntegerType CRC::BoundedConstexprValue(IntegerType x)
|
||||
template <typename CRCType, crcpp_uint16 CRCWidth>
|
||||
inline CRCType CRC::CalculateRemainderBits(unsigned char byte, crcpp_size numBits, const Parameters<CRCType, CRCWidth> & parameters, CRCType remainder)
|
||||
{
|
||||
return (x < IntegerType(0)) ? IntegerType(0) : x;
|
||||
// Slightly different implementations based on the parameters. The current implementations try to eliminate as much
|
||||
// computation from the inner loop (looping over each bit) as possible.
|
||||
if (parameters.reflectInput)
|
||||
{
|
||||
CRCType polynomial = CRC::Reflect(parameters.polynomial, CRCWidth);
|
||||
remainder = static_cast<CRCType>(remainder ^ byte);
|
||||
|
||||
// An optimizing compiler might choose to unroll this loop.
|
||||
for (crcpp_size i = 0; i < numBits; ++i)
|
||||
{
|
||||
#ifdef CRCPP_BRANCHLESS
|
||||
// Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following:
|
||||
// if (remainder & 1)
|
||||
// remainder = (remainder >> 1) ^ polynomial;
|
||||
// else
|
||||
// remainder >>= 1;
|
||||
remainder = static_cast<CRCType>((remainder >> 1) ^ ((remainder & 1) * polynomial));
|
||||
#else
|
||||
remainder = static_cast<CRCType>((remainder & 1) ? ((remainder >> 1) ^ polynomial) : (remainder >> 1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (CRCWidth >= CHAR_BIT)
|
||||
{
|
||||
static crcpp_constexpr CRCType CRC_WIDTH_MINUS_ONE(CRCWidth - CRCType(1));
|
||||
#ifndef CRCPP_BRANCHLESS
|
||||
static crcpp_constexpr CRCType CRC_HIGHEST_BIT_MASK(CRCType(1) << CRC_WIDTH_MINUS_ONE);
|
||||
#endif
|
||||
// The conditional expression is used to avoid a -Wshift-count-overflow warning.
|
||||
static crcpp_constexpr CRCType SHIFT((CRCWidth >= CHAR_BIT) ? static_cast<CRCType>(CRCWidth - CHAR_BIT) : 0);
|
||||
|
||||
remainder = static_cast<CRCType>(remainder ^ (static_cast<CRCType>(byte) << SHIFT));
|
||||
|
||||
// An optimizing compiler might choose to unroll this loop.
|
||||
for (crcpp_size i = 0; i < numBits; ++i)
|
||||
{
|
||||
#ifdef CRCPP_BRANCHLESS
|
||||
// Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following:
|
||||
// if (remainder & CRC_HIGHEST_BIT_MASK)
|
||||
// remainder = (remainder << 1) ^ parameters.polynomial;
|
||||
// else
|
||||
// remainder <<= 1;
|
||||
remainder = static_cast<CRCType>((remainder << 1) ^ (((remainder >> CRC_WIDTH_MINUS_ONE) & 1) * parameters.polynomial));
|
||||
#else
|
||||
remainder = static_cast<CRCType>((remainder & CRC_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ parameters.polynomial) : (remainder << 1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static crcpp_constexpr CRCType CHAR_BIT_MINUS_ONE(CHAR_BIT - 1);
|
||||
#ifndef CRCPP_BRANCHLESS
|
||||
static crcpp_constexpr CRCType CHAR_BIT_HIGHEST_BIT_MASK(CRCType(1) << CHAR_BIT_MINUS_ONE);
|
||||
#endif
|
||||
// The conditional expression is used to avoid a -Wshift-count-overflow warning.
|
||||
static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast<CRCType>(CHAR_BIT - CRCWidth) : 0);
|
||||
|
||||
CRCType polynomial = static_cast<CRCType>(parameters.polynomial << SHIFT);
|
||||
remainder = static_cast<CRCType>((remainder << SHIFT) ^ byte);
|
||||
|
||||
// An optimizing compiler might choose to unroll this loop.
|
||||
for (crcpp_size i = 0; i < numBits; ++i)
|
||||
{
|
||||
#ifdef CRCPP_BRANCHLESS
|
||||
// Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following:
|
||||
// if (remainder & CHAR_BIT_HIGHEST_BIT_MASK)
|
||||
// remainder = (remainder << 1) ^ polynomial;
|
||||
// else
|
||||
// remainder <<= 1;
|
||||
remainder = static_cast<CRCType>((remainder << 1) ^ (((remainder >> CHAR_BIT_MINUS_ONE) & 1) * polynomial));
|
||||
#else
|
||||
remainder = static_cast<CRCType>((remainder & CHAR_BIT_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ polynomial) : (remainder << 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
remainder = static_cast<CRCType>(remainder >> SHIFT);
|
||||
}
|
||||
|
||||
return remainder;
|
||||
}
|
||||
|
||||
#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS
|
||||
@@ -909,6 +1148,25 @@ inline const CRC::Parameters<crcpp_uint8, 6> & CRC::CRC_6_ITU()
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-6 NR.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory
|
||||
footprint.
|
||||
@note CRC-6 NR has the following parameters and check value:
|
||||
- polynomial = 0x21
|
||||
- initial value = 0x00
|
||||
- final XOR = 0x00
|
||||
- reflect input = false
|
||||
- reflect output = false
|
||||
- check value = 0x15
|
||||
@return CRC-6 NR parameters
|
||||
*/
|
||||
inline const CRC::Parameters<crcpp_uint8, 6> & CRC::CRC_6_NR()
|
||||
{
|
||||
static const Parameters<crcpp_uint8, 6> parameters = { 0x21, 0x00, 0x00, false, false };
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-7 JEDEC.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory footprint.
|
||||
@@ -965,6 +1223,24 @@ inline const CRC::Parameters<crcpp_uint8, 8> & CRC::CRC_8_EBU()
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-8 HDLC (ISO/IEC 13239:2002).
|
||||
@note The parameters are static and are delayed-constructed to reduce memory footprint.
|
||||
@note CRC-8 HDLC has the following parameters and check value:
|
||||
- polynomial = 0x07
|
||||
- initial value = 0xFF
|
||||
- final XOR = 0xFF
|
||||
- reflect input = true
|
||||
- reflect output = true
|
||||
- check value = 0x2F
|
||||
@return CRC-8 HDLC parameters
|
||||
*/
|
||||
inline const CRC::Parameters<crcpp_uint8, 8> & CRC::CRC_8_HDLC()
|
||||
{
|
||||
static const Parameters<crcpp_uint8, 8> parameters = { 0x07, 0xFF, 0xFF, true, true };
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-8 MAXIM (aka CRC-8 DOW-CRC).
|
||||
@note The parameters are static and are delayed-constructed to reduce memory footprint.
|
||||
@@ -1001,6 +1277,24 @@ inline const CRC::Parameters<crcpp_uint8, 8> & CRC::CRC_8_WCDMA()
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-8 LTE.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory footprint.
|
||||
@note CRC-8 LTE has the following parameters and check value:
|
||||
- polynomial = 0x9B
|
||||
- initial value = 0x00
|
||||
- final XOR = 0x00
|
||||
- reflect input = false
|
||||
- reflect output = false
|
||||
- check value = 0xEA
|
||||
@return CRC-8 LTE parameters
|
||||
*/
|
||||
inline const CRC::Parameters<crcpp_uint8, 8> & CRC::CRC_8_LTE()
|
||||
{
|
||||
static const Parameters<crcpp_uint8, 8> parameters = { 0x9B, 0x00, 0x00, false, false };
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-10 ITU.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory footprint.
|
||||
@@ -1055,6 +1349,25 @@ inline const CRC::Parameters<crcpp_uint16, 11> & CRC::CRC_11()
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-11 NR.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory
|
||||
footprint.
|
||||
@note CRC-11 NR has the following parameters and check value:
|
||||
- polynomial = 0x621
|
||||
- initial value = 0x000
|
||||
- final XOR = 0x000
|
||||
- reflect input = false
|
||||
- reflect output = false
|
||||
- check value = 0x5CA
|
||||
@return CRC-11 NR parameters
|
||||
*/
|
||||
inline const CRC::Parameters<crcpp_uint16, 11> & CRC::CRC_11_NR()
|
||||
{
|
||||
static const Parameters<crcpp_uint16, 11> parameters = { 0x621, 0x000, 0x000, false, false };
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-12 CDMA2000.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory footprint.
|
||||
@@ -1218,6 +1531,24 @@ inline const CRC::Parameters<crcpp_uint16, 16> & CRC::CRC_16_CCITTFALSE()
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-16 MCRF4XX.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory footprint.
|
||||
@note CRC-16 MCRF4XX has the following parameters and check value:
|
||||
- polynomial = 0x1021
|
||||
- initial value = 0xFFFF
|
||||
- final XOR = 0x0000
|
||||
- reflect input = true
|
||||
- reflect output = true
|
||||
- check value = 0x6F91
|
||||
@return CRC-16 MCRF4XX parameters
|
||||
*/
|
||||
inline const CRC::Parameters<crcpp_uint16, 16> & CRC::CRC_16_MCRF4XX()
|
||||
{
|
||||
static const Parameters<crcpp_uint16, 16> parameters = { 0x1021, 0xFFFF, 0x0000, true, true};
|
||||
return parameters;
|
||||
}
|
||||
|
||||
#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-16 CDMA2000.
|
||||
@@ -1237,6 +1568,24 @@ inline const CRC::Parameters<crcpp_uint16, 16> & CRC::CRC_16_CDMA2000()
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-16 CMS.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory footprint.
|
||||
@note CRC-16 CMS has the following parameters and check value:
|
||||
- polynomial = 0x8005
|
||||
- initial value = 0xFFFF
|
||||
- final XOR = 0x0000
|
||||
- reflect input = false
|
||||
- reflect output = false
|
||||
- check value = 0xAEE7
|
||||
@return CRC-16 CMS parameters
|
||||
*/
|
||||
inline const CRC::Parameters<crcpp_uint16, 16> & CRC::CRC_16_CMS()
|
||||
{
|
||||
static const Parameters<crcpp_uint16, 16> parameters = { 0x8005, 0xFFFF, 0x0000, false, false };
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-16 DECT-R (aka CRC-16 R-CRC).
|
||||
@note The parameters are static and are delayed-constructed to reduce memory footprint.
|
||||
@@ -1400,6 +1749,7 @@ inline const CRC::Parameters<crcpp_uint16, 16> & CRC::CRC_16_USB()
|
||||
static const Parameters<crcpp_uint16, 16> parameters = { 0x8005, 0xFFFF, 0xFFFF, true, true };
|
||||
return parameters;
|
||||
}
|
||||
|
||||
#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS
|
||||
|
||||
/**
|
||||
@@ -1529,6 +1879,63 @@ inline const CRC::Parameters<crcpp_uint32, 24> & CRC::CRC_24_FLEXRAYB()
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-24 LTE-A/NR-A.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory
|
||||
footprint.
|
||||
@note CRC-24 LTE-A has the following parameters and check value:
|
||||
- polynomial = 0x864CFB
|
||||
- initial value = 0x000000
|
||||
- final XOR = 0x000000
|
||||
- reflect input = false
|
||||
- reflect output = false
|
||||
- check value = 0xCDE703
|
||||
@return CRC-24 LTE-A parameters
|
||||
*/
|
||||
inline const CRC::Parameters<crcpp_uint32, 24> & CRC::CRC_24_LTEA()
|
||||
{
|
||||
static const Parameters<crcpp_uint32, 24> parameters = { 0x864CFB, 0x000000, 0x000000, false, false };
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-24 LTE-B/NR-B.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory
|
||||
footprint.
|
||||
@note CRC-24 LTE-B has the following parameters and check value:
|
||||
- polynomial = 0x800063
|
||||
- initial value = 0x000000
|
||||
- final XOR = 0x000000
|
||||
- reflect input = false
|
||||
- reflect output = false
|
||||
- check value = 0x23EF52
|
||||
@return CRC-24 LTE-B parameters
|
||||
*/
|
||||
inline const CRC::Parameters<crcpp_uint32, 24> & CRC::CRC_24_LTEB()
|
||||
{
|
||||
static const Parameters<crcpp_uint32, 24> parameters = { 0x800063, 0x000000, 0x000000, false, false };
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-24 NR-C.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory
|
||||
footprint.
|
||||
@note CRC-24 NR-C has the following parameters and check value:
|
||||
- polynomial = 0xB2B117
|
||||
- initial value = 0x000000
|
||||
- final XOR = 0x000000
|
||||
- reflect input = false
|
||||
- reflect output = false
|
||||
- check value = 0xF48279
|
||||
@return CRC-24 NR-C parameters
|
||||
*/
|
||||
inline const CRC::Parameters<crcpp_uint32, 24> & CRC::CRC_24_NRC()
|
||||
{
|
||||
static const Parameters<crcpp_uint32, 24> parameters = { 0xB2B117, 0x000000, 0x000000, false, false };
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Returns a set of parameters for CRC-30 CDMA.
|
||||
@note The parameters are static and are delayed-constructed to reduce memory footprint.
|
||||
@@ -1700,4 +2107,8 @@ inline const CRC::Parameters<crcpp_uint64, 64> & CRC::CRC_64()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // CRCPP_CRC_H_
|
||||
|
||||
14
src/3rdParty/libE57Format/include/CMakeLists.txt
vendored
14
src/3rdParty/libE57Format/include/CMakeLists.txt
vendored
@@ -1,13 +1,14 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# Copyright 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
target_sources( ${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57Exception.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57Format.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57SimpleData.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57SimpleReader.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57SimpleWriter.h
|
||||
E57Exception.h
|
||||
E57Format.h
|
||||
E57SimpleData.h
|
||||
E57SimpleReader.h
|
||||
E57SimpleWriter.h
|
||||
E57Version.h
|
||||
)
|
||||
|
||||
#install(
|
||||
@@ -17,6 +18,7 @@ target_sources( ${PROJECT_NAME}
|
||||
# E57SimpleData.h
|
||||
# E57SimpleReader.h
|
||||
# E57SimpleWriter.h
|
||||
# E57Version.h
|
||||
# DESTINATION
|
||||
# include/E57Format
|
||||
#)
|
||||
|
||||
420
src/3rdParty/libE57Format/include/E57Exception.h
vendored
420
src/3rdParty/libE57Format/include/E57Exception.h
vendored
@@ -27,110 +27,370 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/// @file E57Exception.h Exception handling for E57 API.
|
||||
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "E57Export.h"
|
||||
|
||||
#ifndef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
// Used to mark unused parameters to indicate intent and suppress warnings.
|
||||
#define E57_UNUSED( expr ) (void)( expr )
|
||||
#endif
|
||||
|
||||
// C++14 does not support the [[deprecated]] attribute on enumerators.
|
||||
// Turn on enumerator deprecation notices if we are compiling with C++17 or later.
|
||||
#if ( ( defined( _MSVC_LANG ) && _MSVC_LANG >= 201703L ) || __cplusplus >= 201703L )
|
||||
#define E57_DEPRECATED_ENUM( str ) [[deprecated( str )]]
|
||||
#else
|
||||
#define E57_DEPRECATED_ENUM( str )
|
||||
#endif
|
||||
|
||||
namespace e57
|
||||
{
|
||||
//! @brief Numeric error identifiers used in E57Exception
|
||||
/// @brief Numeric error identifiers used in E57Exception
|
||||
enum ErrorCode
|
||||
{
|
||||
// N.B. *** When changing error strings here, remember to update the error
|
||||
// strings in E57Exception.cpp ****
|
||||
E57_SUCCESS = 0, //!< operation was successful
|
||||
E57_ERROR_BAD_CV_HEADER = 1, //!< a CompressedVector binary header was bad
|
||||
E57_ERROR_BAD_CV_PACKET = 2, //!< a CompressedVector binary packet was bad
|
||||
E57_ERROR_CHILD_INDEX_OUT_OF_BOUNDS = 3, //!< a numerical index identifying a child was out of bounds
|
||||
E57_ERROR_SET_TWICE = 4, //!< attempted to set an existing child element to a new value
|
||||
E57_ERROR_HOMOGENEOUS_VIOLATION = 5, //!< attempted to add an E57 Element that would have made the children
|
||||
//!< of a homogeneous Vector have different types
|
||||
E57_ERROR_VALUE_NOT_REPRESENTABLE = 6, //!< a value could not be represented in the requested type
|
||||
E57_ERROR_SCALED_VALUE_NOT_REPRESENTABLE = 7, //!< after scaling the result could not be represented in the
|
||||
//!< requested type
|
||||
E57_ERROR_REAL64_TOO_LARGE = 8, //!< a 64 bit IEEE float was too large to store in a 32 bit IEEE float
|
||||
E57_ERROR_EXPECTING_NUMERIC = 9, //!< Expecting numeric representation in user's buffer, found ustring
|
||||
E57_ERROR_EXPECTING_USTRING = 10, //!< Expecting string representation in user's buffer, found numeric
|
||||
E57_ERROR_INTERNAL = 11, //!< An unrecoverable inconsistent internal state was detected
|
||||
E57_ERROR_BAD_XML_FORMAT = 12, //!< E57 primitive not encoded in XML correctly
|
||||
E57_ERROR_XML_PARSER = 13, //!< XML not well formed
|
||||
E57_ERROR_BAD_API_ARGUMENT = 14, //!< bad API function argument provided by user
|
||||
E57_ERROR_FILE_IS_READ_ONLY = 15, //!< can't modify read only file
|
||||
E57_ERROR_BAD_CHECKSUM = 16, //!< checksum mismatch, file is corrupted
|
||||
E57_ERROR_OPEN_FAILED = 17, //!< open() failed
|
||||
E57_ERROR_CLOSE_FAILED = 18, //!< close() failed
|
||||
E57_ERROR_READ_FAILED = 19, //!< read() failed
|
||||
E57_ERROR_WRITE_FAILED = 20, //!< write() failed
|
||||
E57_ERROR_LSEEK_FAILED = 21, //!< lseek() failed
|
||||
E57_ERROR_PATH_UNDEFINED = 22, //!< E57 element path well formed but not defined
|
||||
E57_ERROR_BAD_BUFFER = 23, //!< bad SourceDestBuffer
|
||||
E57_ERROR_NO_BUFFER_FOR_ELEMENT = 24, //!< no buffer specified for an element in CompressedVectorNode during
|
||||
//!< write
|
||||
E57_ERROR_BUFFER_SIZE_MISMATCH = 25, //!< SourceDestBuffers not all same size
|
||||
E57_ERROR_BUFFER_DUPLICATE_PATHNAME = 26, //!< duplicate pathname in CompressedVectorNode read/write
|
||||
E57_ERROR_BAD_FILE_SIGNATURE = 27, //!< file signature not "ASTM-E57"
|
||||
E57_ERROR_UNKNOWN_FILE_VERSION = 28, //!< incompatible file version
|
||||
E57_ERROR_BAD_FILE_LENGTH = 29, //!< size in file header not same as actual
|
||||
E57_ERROR_XML_PARSER_INIT = 30, //!< XML parser failed to initialize
|
||||
E57_ERROR_DUPLICATE_NAMESPACE_PREFIX = 31, //!< namespace prefix already defined
|
||||
E57_ERROR_DUPLICATE_NAMESPACE_URI = 32, //!< namespace URI already defined
|
||||
E57_ERROR_BAD_PROTOTYPE = 33, //!< bad prototype in CompressedVectorNode
|
||||
E57_ERROR_BAD_CODECS = 34, //!< bad codecs in CompressedVectorNode
|
||||
E57_ERROR_VALUE_OUT_OF_BOUNDS = 35, //!< element value out of min/max bounds
|
||||
E57_ERROR_CONVERSION_REQUIRED = 36, //!< conversion required to assign element value, but not requested
|
||||
E57_ERROR_BAD_PATH_NAME = 37, //!< E57 path name is not well formed
|
||||
E57_ERROR_NOT_IMPLEMENTED = 38, //!< functionality not implemented
|
||||
E57_ERROR_BAD_NODE_DOWNCAST = 39, //!< bad downcast from Node to specific node type
|
||||
E57_ERROR_WRITER_NOT_OPEN = 40, //!< CompressedVectorWriter is no longer open
|
||||
E57_ERROR_READER_NOT_OPEN = 41, //!< CompressedVectorReader is no longer open
|
||||
E57_ERROR_NODE_UNATTACHED = 42, //!< node is not yet attached to tree of ImageFile
|
||||
E57_ERROR_ALREADY_HAS_PARENT = 43, //!< node already has a parent
|
||||
E57_ERROR_DIFFERENT_DEST_IMAGEFILE = 44, //!< nodes were constructed with different destImageFiles
|
||||
E57_ERROR_IMAGEFILE_NOT_OPEN = 45, //!< destImageFile is no longer open
|
||||
E57_ERROR_BUFFERS_NOT_COMPATIBLE = 46, //!< SourceDestBuffers not compatible with previously given ones
|
||||
E57_ERROR_TOO_MANY_WRITERS = 47, //!< too many open CompressedVectorWriters of an ImageFile
|
||||
E57_ERROR_TOO_MANY_READERS = 48, //!< too many open CompressedVectorReaders of an ImageFile
|
||||
E57_ERROR_BAD_CONFIGURATION = 49, //!< bad configuration string
|
||||
E57_ERROR_INVARIANCE_VIOLATION = 50 //!< class invariance constraint violation in debug mode
|
||||
// NOTE: When changing error strings here, remember to update the error strings in
|
||||
// E57Exception.cpp
|
||||
|
||||
Success = 0, ///< operation was successful
|
||||
|
||||
ErrorBadCVHeader = 1, ///< a CompressedVector binary header was bad
|
||||
ErrorBadCVPacket = 2, ///< a CompressedVector binary packet was bad
|
||||
ErrorChildIndexOutOfBounds = 3, ///< a numerical index identifying a child was out of bounds
|
||||
ErrorSetTwice = 4, ///< attempted to set an existing child element to a new value
|
||||
|
||||
/// @brief attempted to add an element that would have made the children of a homogeneous
|
||||
/// ::TypeVector have different types
|
||||
ErrorHomogeneousViolation = 5,
|
||||
|
||||
/// a value could not be represented in the requested type
|
||||
ErrorValueNotRepresentable = 6,
|
||||
|
||||
/// after scaling the result could not be represented in the requested type
|
||||
ErrorScaledValueNotRepresentable = 7,
|
||||
|
||||
/// a 64 bit IEEE float was too large to store in a 32 bit IEEE float
|
||||
ErrorReal64TooLarge = 8,
|
||||
|
||||
/// expecting numeric representation in user's buffer, found ustring
|
||||
ErrorExpectingNumeric = 9,
|
||||
|
||||
/// expecting string representation in user's buffer, found numeric
|
||||
ErrorExpectingUString = 10,
|
||||
|
||||
ErrorInternal = 11, ///< An unrecoverable inconsistent internal state was detected
|
||||
ErrorBadXMLFormat = 12, ///< E57 primitive not encoded in XML correctly
|
||||
ErrorXMLParser = 13, ///< XML not well formed
|
||||
ErrorBadAPIArgument = 14, ///< bad API function argument provided by user
|
||||
ErrorFileReadOnly = 15, ///< can't modify read only file
|
||||
ErrorBadChecksum = 16, ///< checksum mismatch, file is corrupted
|
||||
ErrorOpenFailed = 17, ///< open() failed
|
||||
ErrorCloseFailed = 18, ///< close() failed
|
||||
ErrorReadFailed = 19, ///< read() failed
|
||||
ErrorWriteFailed = 20, ///< write() failed
|
||||
ErrorSeekFailed = 21, ///< lseek() failed
|
||||
ErrorPathUndefined = 22, ///< element path well formed but not defined
|
||||
ErrorBadBuffer = 23, ///< bad SourceDestBuffer
|
||||
|
||||
/// no buffer specified for an element in CompressedVectorNode during write
|
||||
ErrorNoBufferForElement = 24,
|
||||
|
||||
ErrorBufferSizeMismatch = 25, ///< SourceDestBuffers not all same size
|
||||
ErrorBufferDuplicatePathName = 26, ///< duplicate pathname in CompressedVectorNode read/write
|
||||
ErrorBadFileSignature = 27, ///< file signature not "ASTM-E57"
|
||||
ErrorUnknownFileVersion = 28, ///< incompatible file version
|
||||
ErrorBadFileLength = 29, ///< size in file header not same as actual
|
||||
ErrorXMLParserInit = 30, ///< XML parser failed to initialize
|
||||
ErrorDuplicateNamespacePrefix = 31, ///< namespace prefix already defined
|
||||
ErrorDuplicateNamespaceURI = 32, ///< namespace URI already defined
|
||||
ErrorBadPrototype = 33, ///< bad prototype in CompressedVectorNode
|
||||
ErrorBadCodecs = 34, ///< bad codecs in CompressedVectorNode
|
||||
ErrorValueOutOfBounds = 35, ///< element value out of min/max bounds
|
||||
|
||||
/// conversion required to assign element value, but not requested
|
||||
ErrorConversionRequired = 36,
|
||||
|
||||
ErrorBadPathName = 37, ///< E57 path name is not well formed
|
||||
ErrorNotImplemented = 38, ///< functionality not implemented
|
||||
ErrorBadNodeDowncast = 39, ///< bad downcast from Node to specific node type
|
||||
ErrorWriterNotOpen = 40, ///< CompressedVectorWriter is no longer open
|
||||
ErrorReaderNotOpen = 41, ///< CompressedVectorReader is no longer open
|
||||
ErrorNodeUnattached = 42, ///< node is not yet attached to tree of ImageFile
|
||||
ErrorAlreadyHasParent = 43, ///< node already has a parent
|
||||
ErrorDifferentDestImageFile = 44, ///< nodes were constructed with different destImageFiles
|
||||
ErrorImageFileNotOpen = 45, ///< destImageFile is no longer open
|
||||
|
||||
/// SourceDestBuffers not compatible with previously given ones
|
||||
ErrorBuffersNotCompatible = 46,
|
||||
|
||||
ErrorTooManyWriters = 47, ///< too many open CompressedVectorWriters of an ImageFile
|
||||
ErrorTooManyReaders = 48, ///< too many open CompressedVectorReaders of an ImageFile
|
||||
ErrorBadConfiguration = 49, ///< bad configuration string
|
||||
ErrorInvarianceViolation = 50, ///< class invariance constraint violation in debug mode
|
||||
|
||||
/// an invalid node type was passed in Data3D pointFields
|
||||
ErrorInvalidNodeType = 51,
|
||||
|
||||
/// passed an invalid value in Data3D pointFields
|
||||
ErrorInvalidData3DValue = 52,
|
||||
|
||||
/// Older versions of this library (and E57RefImpl) incorrectly set the "fileOffset" to 0
|
||||
/// when "recordCount" is 0. "fileOffset" must be greater than 0 (Table 9 in the standard).
|
||||
ErrorData3DReadInvalidZeroRecords = 53,
|
||||
|
||||
/// @deprecated Will be removed in 4.0. Use e57::Success.
|
||||
E57_SUCCESS E57_DEPRECATED_ENUM( "Will be removed in 4.0. Use Success." ) = Success,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadCVHeader.
|
||||
E57_ERROR_BAD_CV_HEADER E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadCVHeader." ) = ErrorBadCVHeader,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadCVPacket.
|
||||
E57_ERROR_BAD_CV_PACKET E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadCVPacket." ) = ErrorBadCVPacket,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorChildIndexOutOfBounds.
|
||||
E57_ERROR_CHILD_INDEX_OUT_OF_BOUNDS E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorChildIndexOutOfBounds." ) = ErrorChildIndexOutOfBounds,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorSetTwice.
|
||||
E57_ERROR_SET_TWICE E57_DEPRECATED_ENUM( "Will be removed in 4.0. Use ErrorSetTwice." ) =
|
||||
ErrorSetTwice,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorHomogeneousViolation.
|
||||
E57_ERROR_HOMOGENEOUS_VIOLATION E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorHomogeneousViolation." ) = ErrorHomogeneousViolation,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorValueNotRepresentable.
|
||||
E57_ERROR_VALUE_NOT_REPRESENTABLE E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorValueNotRepresentable." ) = ErrorValueNotRepresentable,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorScaledValueNotRepresentable.
|
||||
E57_ERROR_SCALED_VALUE_NOT_REPRESENTABLE E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorScaledValueNotRepresentable." ) =
|
||||
ErrorScaledValueNotRepresentable,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorReal64TooLarge.
|
||||
E57_ERROR_REAL64_TOO_LARGE E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorReal64TooLarge." ) = ErrorReal64TooLarge,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorExpectingNumeric.
|
||||
E57_ERROR_EXPECTING_NUMERIC E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorExpectingNumeric." ) = ErrorExpectingNumeric,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorExpectingUString.
|
||||
E57_ERROR_EXPECTING_USTRING E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorExpectingUString." ) = ErrorExpectingUString,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorInternal.
|
||||
E57_ERROR_INTERNAL E57_DEPRECATED_ENUM( "Will be removed in 4.0. Use ErrorInternal." ) =
|
||||
ErrorInternal,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadXMLFormat.
|
||||
E57_ERROR_BAD_XML_FORMAT E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadXMLFormat." ) = ErrorBadXMLFormat,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorXMLParser.
|
||||
E57_ERROR_XML_PARSER E57_DEPRECATED_ENUM( "Will be removed in 4.0. Use ErrorXMLParser." ) =
|
||||
ErrorXMLParser,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadAPIArgument.
|
||||
E57_ERROR_BAD_API_ARGUMENT E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadAPIArgument." ) = ErrorBadAPIArgument,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorFileReadOnly.
|
||||
E57_ERROR_FILE_IS_READ_ONLY E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorFileReadOnly." ) = ErrorFileReadOnly,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadChecksum.
|
||||
E57_ERROR_BAD_CHECKSUM E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadChecksum." ) = ErrorBadChecksum,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorOpenFailed.
|
||||
E57_ERROR_OPEN_FAILED E57_DEPRECATED_ENUM( "Will be removed in 4.0. Use ErrorOpenFailed." ) =
|
||||
ErrorOpenFailed,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorCloseFailed.
|
||||
E57_ERROR_CLOSE_FAILED E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorCloseFailed." ) = ErrorCloseFailed,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorReadFailed.
|
||||
E57_ERROR_READ_FAILED E57_DEPRECATED_ENUM( "Will be removed in 4.0. Use ErrorReadFailed." ) =
|
||||
ErrorReadFailed,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorWriteFailed.
|
||||
E57_ERROR_WRITE_FAILED E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorWriteFailed." ) = ErrorWriteFailed,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorSeekFailed.
|
||||
E57_ERROR_LSEEK_FAILED E57_DEPRECATED_ENUM( "Will be removed in 4.0. Use ErrorSeekFailed." ) =
|
||||
ErrorSeekFailed,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorPathUndefined.
|
||||
E57_ERROR_PATH_UNDEFINED E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorPathUndefined." ) = ErrorPathUndefined,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadBuffer.
|
||||
E57_ERROR_BAD_BUFFER E57_DEPRECATED_ENUM( "Will be removed in 4.0. Use ErrorBadBuffer." ) =
|
||||
ErrorBadBuffer,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorNoBufferForElement.
|
||||
E57_ERROR_NO_BUFFER_FOR_ELEMENT E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorNoBufferForElement." ) = ErrorNoBufferForElement,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBufferSizeMismatch.
|
||||
E57_ERROR_BUFFER_SIZE_MISMATCH E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBufferSizeMismatch." ) = ErrorBufferSizeMismatch,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBufferDuplicatePathName.
|
||||
E57_ERROR_BUFFER_DUPLICATE_PATHNAME E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBufferDuplicatePathName." ) =
|
||||
ErrorBufferDuplicatePathName,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadFileSignature.
|
||||
E57_ERROR_BAD_FILE_SIGNATURE E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadFileSignature." ) = ErrorBadFileSignature,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorUnknownFileVersion.
|
||||
E57_ERROR_UNKNOWN_FILE_VERSION E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorUnknownFileVersion." ) = ErrorUnknownFileVersion,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadFileLength.
|
||||
E57_ERROR_BAD_FILE_LENGTH E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadFileLength." ) = ErrorBadFileLength,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorXMLParserInit.
|
||||
E57_ERROR_XML_PARSER_INIT E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorXMLParserInit." ) = ErrorXMLParserInit,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorDuplicateNamespacePrefix.
|
||||
E57_ERROR_DUPLICATE_NAMESPACE_PREFIX E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorDuplicateNamespacePrefix." ) =
|
||||
ErrorDuplicateNamespacePrefix,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorDuplicateNamespaceURI.
|
||||
E57_ERROR_DUPLICATE_NAMESPACE_URI E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorDuplicateNamespaceURI." ) = ErrorDuplicateNamespaceURI,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadPrototype.
|
||||
E57_ERROR_BAD_PROTOTYPE E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadPrototype." ) = ErrorBadPrototype,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadCodecs.
|
||||
E57_ERROR_BAD_CODECS E57_DEPRECATED_ENUM( "Will be removed in 4.0. Use ErrorBadCodecs." ) =
|
||||
ErrorBadCodecs,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorValueOutOfBounds.
|
||||
E57_ERROR_VALUE_OUT_OF_BOUNDS E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorValueOutOfBounds." ) = ErrorValueOutOfBounds,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorConversionRequired.
|
||||
E57_ERROR_CONVERSION_REQUIRED E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorConversionRequired." ) = ErrorConversionRequired,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadPathName.
|
||||
E57_ERROR_BAD_PATH_NAME E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadPathName." ) = ErrorBadPathName,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorNotImplemented.
|
||||
E57_ERROR_NOT_IMPLEMENTED E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorNotImplemented." ) = ErrorNotImplemented,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadNodeDowncast.
|
||||
E57_ERROR_BAD_NODE_DOWNCAST E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadNodeDowncast." ) = ErrorBadNodeDowncast,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorWriterNotOpen.
|
||||
E57_ERROR_WRITER_NOT_OPEN E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorWriterNotOpen." ) = ErrorWriterNotOpen,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorReaderNotOpen.
|
||||
E57_ERROR_READER_NOT_OPEN E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorReaderNotOpen." ) = ErrorReaderNotOpen,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorNodeUnattached.
|
||||
E57_ERROR_NODE_UNATTACHED E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorNodeUnattached." ) = ErrorNodeUnattached,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorAlreadyHasParent.
|
||||
E57_ERROR_ALREADY_HAS_PARENT E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorAlreadyHasParent." ) = ErrorAlreadyHasParent,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorDifferentDestImageFile.
|
||||
E57_ERROR_DIFFERENT_DEST_IMAGEFILE E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorDifferentDestImageFile." ) = ErrorDifferentDestImageFile,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorImageFileNotOpen.
|
||||
E57_ERROR_IMAGEFILE_NOT_OPEN E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorImageFileNotOpen." ) = ErrorImageFileNotOpen,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBuffersNotCompatible.
|
||||
E57_ERROR_BUFFERS_NOT_COMPATIBLE E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBuffersNotCompatible." ) = ErrorBuffersNotCompatible,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorTooManyWriters.
|
||||
E57_ERROR_TOO_MANY_WRITERS E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorTooManyWriters." ) = ErrorTooManyWriters,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorTooManyReaders.
|
||||
E57_ERROR_TOO_MANY_READERS E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorTooManyReaders." ) = ErrorTooManyReaders,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorBadConfiguration.
|
||||
E57_ERROR_BAD_CONFIGURATION E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorBadConfiguration." ) = ErrorBadConfiguration,
|
||||
/// @deprecated Will be removed in 4.0. Use e57::ErrorInvarianceViolation.
|
||||
E57_ERROR_INVARIANCE_VIOLATION E57_DEPRECATED_ENUM(
|
||||
"Will be removed in 4.0. Use ErrorInvarianceViolation." ) = ErrorInvarianceViolation,
|
||||
};
|
||||
|
||||
class E57_DLL E57Exception : public std::exception
|
||||
namespace Utilities
|
||||
{
|
||||
E57_DLL std::string errorCodeToString( ErrorCode ecode ) noexcept;
|
||||
}
|
||||
|
||||
class E57Exception : public std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override
|
||||
{
|
||||
return "E57 exception";
|
||||
}
|
||||
|
||||
void report( const char *reportingFileName = nullptr, int reportingLineNumber = 0,
|
||||
const char *reportingFunctionName = nullptr, std::ostream &os = std::cout ) const;
|
||||
ErrorCode errorCode() const;
|
||||
std::string context() const;
|
||||
const char *what() const noexcept override;
|
||||
const char *reportingFunctionName = nullptr,
|
||||
std::ostream &os = std::cout ) const noexcept
|
||||
{
|
||||
os << "**** Got an e57 exception: " << errorStr() << std::endl;
|
||||
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
os << " Debug info: " << std::endl;
|
||||
os << " context: " << context_ << std::endl;
|
||||
os << " sourceFunctionName: " << sourceFunctionName_ << std::endl;
|
||||
if ( reportingFunctionName != nullptr )
|
||||
{
|
||||
os << " reportingFunctionName: " << reportingFunctionName << std::endl;
|
||||
}
|
||||
|
||||
/*** Add a line in error message that a smart editor (gnu emacs) can
|
||||
* interpret as a link to the source code: */
|
||||
os << sourceFileName_ << "(" << sourceLineNumber_ << ") : error C" << errorCode_
|
||||
<< ": <--- occurred on" << std::endl;
|
||||
if ( reportingFileName != nullptr )
|
||||
{
|
||||
os << reportingFileName << "(" << reportingLineNumber
|
||||
<< ") : error C0: <--- reported on" << std::endl;
|
||||
}
|
||||
#else
|
||||
E57_UNUSED( reportingFileName );
|
||||
E57_UNUSED( reportingLineNumber );
|
||||
E57_UNUSED( reportingFunctionName );
|
||||
#endif
|
||||
}
|
||||
|
||||
ErrorCode errorCode() const noexcept
|
||||
{
|
||||
return errorCode_;
|
||||
}
|
||||
|
||||
std::string errorStr() const noexcept
|
||||
{
|
||||
return Utilities::errorCodeToString( errorCode_ );
|
||||
}
|
||||
|
||||
const std::string &context() const noexcept
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
|
||||
// For debugging purposes:
|
||||
const char *sourceFileName() const;
|
||||
const char *sourceFunctionName() const;
|
||||
int sourceLineNumber() const;
|
||||
const char *sourceFileName() const noexcept
|
||||
{
|
||||
return sourceFileName_.c_str();
|
||||
}
|
||||
|
||||
//! \cond documentNonPublic The following isn't part of the API, and isn't
|
||||
//! documented.
|
||||
const char *sourceFunctionName() const noexcept
|
||||
{
|
||||
return sourceFunctionName_;
|
||||
}
|
||||
|
||||
int sourceLineNumber() const noexcept
|
||||
{
|
||||
return sourceLineNumber_;
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
E57Exception() = delete;
|
||||
E57Exception( ErrorCode ecode, const std::string &context, const std::string &srcFileName = nullptr,
|
||||
int srcLineNumber = 0, const char *srcFunctionName = nullptr );
|
||||
~E57Exception() noexcept override = default;
|
||||
E57Exception( ErrorCode ecode, std::string context, const char *srcFileName = nullptr,
|
||||
int srcLineNumber = 0, const char *srcFunctionName = nullptr ) :
|
||||
errorCode_( ecode ), context_( std::move( context ) ), sourceFileName_( srcFileName ),
|
||||
sourceFunctionName_( srcFunctionName ), sourceLineNumber_( srcLineNumber )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
protected:
|
||||
private:
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
ErrorCode errorCode_;
|
||||
std::string context_;
|
||||
std::string sourceFileName_;
|
||||
const char *sourceFunctionName_;
|
||||
int sourceLineNumber_;
|
||||
//! \endcond
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
namespace Utilities
|
||||
{
|
||||
// Get latest version of ASTM standard supported, and library id string
|
||||
E57_DLL void getVersions( int &astmMajor, int &astmMinor, std::string &libraryId );
|
||||
|
||||
E57_DLL std::string errorCodeToString( ErrorCode ecode );
|
||||
}
|
||||
}
|
||||
|
||||
1487
src/3rdParty/libE57Format/include/E57Format.h
vendored
1487
src/3rdParty/libE57Format/include/E57Format.h
vendored
File diff suppressed because it is too large
Load Diff
1056
src/3rdParty/libE57Format/include/E57SimpleData.h
vendored
1056
src/3rdParty/libE57Format/include/E57SimpleData.h
vendored
File diff suppressed because it is too large
Load Diff
228
src/3rdParty/libE57Format/include/E57SimpleReader.h
vendored
228
src/3rdParty/libE57Format/include/E57SimpleReader.h
vendored
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
|
||||
* Copyright (c) 2020 PTC Inc.
|
||||
* Copyright (c) 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
@@ -29,158 +30,185 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
//! @file E57SimpleReader.h E57 Simple API for reading E57
|
||||
/// @file
|
||||
/// @brief E57 Simple API for reading E57.
|
||||
/// @details This includes support for the
|
||||
/// [E57_EXT_surface_normals](http://www.libe57.org/E57_EXT_surface_normals.txt) extension.
|
||||
|
||||
#include "E57SimpleData.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
/// Options to the Reader constructor
|
||||
struct E57_DLL ReaderOptions
|
||||
{
|
||||
/// Set how frequently to verify the checksums (see ReadChecksumPolicy).
|
||||
ReadChecksumPolicy checksumPolicy = ChecksumAll;
|
||||
};
|
||||
|
||||
//! @brief Used for reading of the E57 file with E57 Simple API
|
||||
/// @brief Used for reading an E57 file using E57 Simple API.
|
||||
///
|
||||
/// The Reader includes support for the
|
||||
/// [E57_EXT_surface_normals](http://www.libe57.org/E57_EXT_surface_normals.txt) extension.
|
||||
class E57_DLL Reader
|
||||
{
|
||||
public:
|
||||
//! @brief This function is the constructor for the reader class
|
||||
//! @param [in] filePath file path to E57 file
|
||||
Reader( const ustring &filePath );
|
||||
//! @brief This function returns true if the file is open
|
||||
/// @brief Reader constructor
|
||||
/// @param [in] filePath Path to E57 file
|
||||
/// @param [in] options Options to be used for the file
|
||||
Reader( const ustring &filePath, const ReaderOptions &options );
|
||||
|
||||
/// @brief Reader constructor (deprecated)
|
||||
/// @param [in] filePath Path to E57 file
|
||||
/// @deprecated Will be removed in 4.0. Use Reader( const ustring &, const ReaderOptions & )
|
||||
/// instead.
|
||||
[[deprecated( "Will be removed in 4.0. Use Reader( const ustring, const ReaderOptions & "
|
||||
")." )]] // TODO Remove in 4.0
|
||||
explicit Reader( const ustring &filePath );
|
||||
|
||||
/// @brief Returns true if the file is open
|
||||
bool IsOpen() const;
|
||||
|
||||
//! @brief This function closes the file
|
||||
/// @brief Closes the file
|
||||
bool Close();
|
||||
|
||||
//! @name File information
|
||||
//!@{
|
||||
/// @name File information
|
||||
///@{
|
||||
|
||||
//! @brief This function returns the file header information
|
||||
//! @param [out] fileHeader is the main header information
|
||||
//! @return Returns true if successful
|
||||
/// @brief Returns the file header information
|
||||
/// @param [out] fileHeader is the main header information
|
||||
/// @return Returns true if successful
|
||||
bool GetE57Root( E57Root &fileHeader ) const;
|
||||
|
||||
//!@}
|
||||
///@}
|
||||
|
||||
//! @name Image2D
|
||||
//!@{
|
||||
/// @name Image2D
|
||||
///@{
|
||||
|
||||
//! @brief This function returns the total number of Picture Blocks
|
||||
//! @return Returns the number of Image2D blocks
|
||||
/// @brief Returns the total number of Picture Blocks
|
||||
/// @return Returns the number of Image2D blocks
|
||||
int64_t GetImage2DCount() const;
|
||||
|
||||
//! @brief This function returns the image2D header and positions the cursor
|
||||
//! @param [in] imageIndex This in the index into the image2D vector
|
||||
//! @param [out] image2DHeader pointer to the Image2D structure to receive the picture information
|
||||
//! @return Returns true if successful
|
||||
/// @brief Returns the image2D header and positions the cursor
|
||||
/// @param [in] imageIndex This in the index into the image2D vector
|
||||
/// @param [out] image2DHeader pointer to the Image2D structure to receive the picture
|
||||
/// information
|
||||
/// @return Returns true if successful
|
||||
bool ReadImage2D( int64_t imageIndex, Image2D &image2DHeader ) const;
|
||||
|
||||
//! @brief This function returns the size of the image data
|
||||
//! @param [in] imageIndex This in the index into the image2D vector
|
||||
//! @param [out] imageProjection identifies the projection in the image2D.
|
||||
//! @param [out] imageType identifies the image format of the projection.
|
||||
//! @param [out] imageWidth The image width (in pixels).
|
||||
//! @param [out] imageHeight The image height (in pixels).
|
||||
//! @param [out] imageSize This is the total number of bytes for the image blob.
|
||||
//! @param [out] imageMaskType This is E57_PNG_IMAGE_MASK if "imageMask" is defined in the projection
|
||||
//! @param [out] imageVisualType This is image type of the VisualReferenceRepresentation if given.
|
||||
//! @return Returns true if successful
|
||||
bool GetImage2DSizes( int64_t imageIndex, Image2DProjection &imageProjection, Image2DType &imageType,
|
||||
int64_t &imageWidth, int64_t &imageHeight, int64_t &imageSize, Image2DType &imageMaskType,
|
||||
/// @brief Returns the size of the image data
|
||||
/// @param [in] imageIndex This in the index into the image2D vector
|
||||
/// @param [out] imageProjection identifies the projection in the image2D.
|
||||
/// @param [out] imageType identifies the image format of the projection.
|
||||
/// @param [out] imageWidth The image width (in pixels).
|
||||
/// @param [out] imageHeight The image height (in pixels).
|
||||
/// @param [out] imageSize This is the total number of bytes for the image blob.
|
||||
/// @param [out] imageMaskType This is E57_PNG_IMAGE_MASK if "imageMask" is defined in the
|
||||
/// projection
|
||||
/// @param [out] imageVisualType This is image type of the VisualReferenceRepresentation if
|
||||
/// given.
|
||||
/// @return Returns true if successful
|
||||
bool GetImage2DSizes( int64_t imageIndex, Image2DProjection &imageProjection,
|
||||
Image2DType &imageType, int64_t &imageWidth, int64_t &imageHeight,
|
||||
int64_t &imageSize, Image2DType &imageMaskType,
|
||||
Image2DType &imageVisualType ) const;
|
||||
|
||||
//! @brief This function reads an image
|
||||
//! @param [in] imageIndex index of the image. Must be less than GetImage2DCount()
|
||||
//! @param [in] imageProjection identifies the projection desired.
|
||||
//! @param [in] imageType identifies the image format desired.
|
||||
//! @param [out] buffer pointer the raw image buffer
|
||||
//! @param [in] start position in the block to start reading
|
||||
//! @param [in] count size of desired chuck or buffer size
|
||||
//! @return Returns the number of bytes transferred.
|
||||
int64_t ReadImage2DData( int64_t imageIndex, Image2DProjection imageProjection, Image2DType imageType,
|
||||
void *buffer, int64_t start, int64_t count ) const;
|
||||
/// @brief Reads an image
|
||||
/// @param [in] imageIndex index of the image. Must be less than GetImage2DCount()
|
||||
/// @param [in] imageProjection identifies the projection desired.
|
||||
/// @param [in] imageType identifies the image format desired.
|
||||
/// @param [out] buffer pointer the raw image buffer
|
||||
/// @param [in] start position in the block to start reading
|
||||
/// @param [in] count size of desired chuck or buffer size
|
||||
/// @return Returns the number of bytes transferred.
|
||||
int64_t ReadImage2DData( int64_t imageIndex, Image2DProjection imageProjection,
|
||||
Image2DType imageType, void *buffer, int64_t start,
|
||||
int64_t count ) const;
|
||||
|
||||
//!@}
|
||||
///@}
|
||||
|
||||
//! @name Data3D
|
||||
//!@{
|
||||
/// @name Data3D
|
||||
///@{
|
||||
|
||||
//! @brief This function returns the total number of Data3D Blocks
|
||||
//! @return Returns number of Data3D blocks.
|
||||
/// @brief Returns the total number of Data3D Blocks
|
||||
/// @return Returns number of Data3D blocks.
|
||||
int64_t GetData3DCount() const;
|
||||
|
||||
//! @brief This function returns the Data3D header
|
||||
//! @param [in] dataIndex This in the index into the images3D vector. Must be less than GetData3DCount().
|
||||
//! @param [out] data3DHeader Data3D header
|
||||
//! @return Returns true if successful
|
||||
/// @brief Returns the Data3D header
|
||||
/// @param [in] dataIndex This in the index into the images3D vector. Must be less than
|
||||
/// GetData3DCount().
|
||||
/// @param [out] data3DHeader Data3D header
|
||||
/// @return Returns true if successful
|
||||
bool ReadData3D( int64_t dataIndex, Data3D &data3DHeader ) const;
|
||||
|
||||
//! @brief This function returns the size of the point data
|
||||
//! @param [in] dataIndex This in the index into the images3D vector. Must be less than GetData3DCount().
|
||||
//! @param [out] rowMax This is the maximum row size
|
||||
//! @param [out] columnMax This is the maximum column size
|
||||
//! @param [out] pointsSize This is the total number of point records
|
||||
//! @param [out] groupsSize This is the total number of group reocrds
|
||||
//! @param [out] countSize This is the maximum point count per group
|
||||
//! @param [out] columnIndex This indicates that the idElementName is "columnIndex"
|
||||
//! @return Return true if successful, false otherwise
|
||||
bool GetData3DSizes( int64_t dataIndex, int64_t &rowMax, int64_t &columnMax, int64_t &pointsSize,
|
||||
int64_t &groupsSize, int64_t &countSize, bool &columnIndex ) const;
|
||||
/// @brief Returns the size of the point data
|
||||
/// @param [in] dataIndex This in the index into the images3D vector. Must be less than
|
||||
/// GetData3DCount().
|
||||
/// @param [out] rowMax This is the maximum row size
|
||||
/// @param [out] columnMax This is the maximum column size
|
||||
/// @param [out] pointsSize This is the total number of point records
|
||||
/// @param [out] groupsSize This is the total number of group records
|
||||
/// @param [out] countSize This is the maximum point count per group
|
||||
/// @param [out] columnIndex This indicates that the idElementName is "columnIndex"
|
||||
/// @return Return true if successful, false otherwise
|
||||
bool GetData3DSizes( int64_t dataIndex, int64_t &rowMax, int64_t &columnMax,
|
||||
int64_t &pointsSize, int64_t &groupsSize, int64_t &countSize,
|
||||
bool &columnIndex ) const;
|
||||
|
||||
//! @brief This function reads the group data into the provided buffers.
|
||||
//! @param [in] dataIndex This in the index into the images3D vector. Must be less than GetData3DCount().
|
||||
//! @param [in] groupCount size of each of the buffers given
|
||||
//! @param [out] idElementValue pointer to the buffer holding indices index for this group
|
||||
//! @param [out] startPointIndex pointer to the buffer holding Starting index in to the "points" data vector for
|
||||
//! the groups
|
||||
//! @param [out] pointCount pointer to the buffer holding size of the groups given
|
||||
//! @return Return true if successful, false otherwise
|
||||
bool ReadData3DGroupsData( int64_t dataIndex, int64_t groupCount, int64_t *idElementValue,
|
||||
/// @brief Reads the group data into the provided buffers.
|
||||
/// @param [in] dataIndex This in the index into the images3D vector. Must be less than
|
||||
/// GetData3DCount().
|
||||
/// @param [in] groupCount size of each of the buffers given
|
||||
/// @param [out] idElementValue pointer to the buffer holding indices index for this group
|
||||
/// @param [out] startPointIndex pointer to the buffer holding Starting index in to the
|
||||
/// "points" data vector for the groups
|
||||
/// @param [out] pointCount pointer to the buffer holding size of the groups given
|
||||
/// @return Return true if successful, false otherwise
|
||||
bool ReadData3DGroupsData( int64_t dataIndex, size_t groupCount, int64_t *idElementValue,
|
||||
int64_t *startPointIndex, int64_t *pointCount ) const;
|
||||
|
||||
//! @brief Use this function to read the actual 3D data
|
||||
//! @details All the non-NULL buffers in buffers have number of elements = pointCount.
|
||||
//! Call the CompressedVectorReader::read() until all data is read.
|
||||
//! @param [in] dataIndex data block index given by the NewData3D
|
||||
//! @param [in] pointCount size of each element buffer.
|
||||
//! @param [in] buffers pointers to user-provided buffers
|
||||
//! @return vector reader setup to read the selected data into the provided buffers
|
||||
/// @brief Use this to read the actual 3D data
|
||||
/// @details All the non-NULL buffers in buffers have number of elements = pointCount.
|
||||
/// Call the CompressedVectorReader::read() until all data is read.
|
||||
/// @param [in] dataIndex data block index
|
||||
/// @param [in] pointCount size of each element buffer.
|
||||
/// @param [in] buffers pointers to user-provided buffers
|
||||
/// @return vector reader setup to read the selected data into the provided buffers
|
||||
CompressedVectorReader SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsData &buffers ) const;
|
||||
const Data3DPointsFloat &buffers ) const;
|
||||
|
||||
//! @brief Use this function to read the actual 3D data
|
||||
//! @details All the non-NULL buffers in buffers have number of elements = pointCount.
|
||||
//! Call the CompressedVectorReader::read() until all data is read.
|
||||
//! @param [in] dataIndex data block index given by the NewData3D
|
||||
//! @param [in] pointCount size of each element buffer.
|
||||
//! @param [in] buffers pointers to user-provided buffers
|
||||
//! @return vector reader setup to read the selected data into the provided buffers
|
||||
/// @overload
|
||||
CompressedVectorReader SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsData_d &buffers ) const;
|
||||
const Data3DPointsDouble &buffers ) const;
|
||||
|
||||
//!@}
|
||||
///@}
|
||||
|
||||
//! @name Foundation API file information
|
||||
//!@{
|
||||
/// @name File information
|
||||
///@{
|
||||
|
||||
//! @brief Returns the file raw E57Root Structure Node
|
||||
/// @brief Returns the file raw E57Root Structure Node
|
||||
StructureNode GetRawE57Root() const;
|
||||
|
||||
//! @brief Returns the raw Data3D Vector Node
|
||||
/// @brief Returns the raw Data3D Vector Node
|
||||
VectorNode GetRawData3D() const;
|
||||
|
||||
//! @brief Returns the raw Image2D Vector Node
|
||||
/// @brief Returns the raw Image2D Vector Node
|
||||
VectorNode GetRawImages2D() const;
|
||||
|
||||
//! @brief Returns the ram ImageFile Node which is need to add enhancements
|
||||
/// @brief Returns the ram ImageFile Node which is need to add enhancements
|
||||
ImageFile GetRawIMF() const;
|
||||
|
||||
//!@}
|
||||
///@}
|
||||
|
||||
//! @cond documentNonPublic The following isn't part of the API, and isn't
|
||||
//! documented.
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
protected:
|
||||
friend class ReaderImpl;
|
||||
|
||||
E57_OBJECT_IMPLEMENTATION( Reader ) // Internal implementation details, not part of API, must be last in object
|
||||
//! @endcond
|
||||
E57_INTERNAL_ACCESS( Reader )
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ReaderImpl> impl_;
|
||||
/// @endcond
|
||||
}; // end Reader class
|
||||
|
||||
} // end namespace e57
|
||||
|
||||
181
src/3rdParty/libE57Format/include/E57SimpleWriter.h
vendored
181
src/3rdParty/libE57Format/include/E57SimpleWriter.h
vendored
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
|
||||
* Copyright (c) 2020 PTC Inc.
|
||||
* Copyright (c) 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
@@ -29,109 +30,161 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
//! @file E57SimpleWriter.h E57 Simple API for writing E57
|
||||
/// @file
|
||||
/// @brief E57 Simple API for writing E57.
|
||||
/// @details This includes support for the
|
||||
/// [E57_EXT_surface_normals](http://www.libe57.org/E57_EXT_surface_normals.txt) extension.
|
||||
|
||||
#include "E57SimpleData.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
/// Options to the Writer constructor
|
||||
struct E57_DLL WriterOptions
|
||||
{
|
||||
/// Optional file guid
|
||||
ustring guid;
|
||||
|
||||
//! @brief Used for writing of the E57 file with E57 Simple API
|
||||
/// Information describing the Coordinate Reference System to be used for the file
|
||||
ustring coordinateMetadata;
|
||||
};
|
||||
|
||||
/// @brief Used for writing an E57 file using the E57 Simple API.
|
||||
///
|
||||
/// The Writer includes support for the
|
||||
/// [E57_EXT_surface_normals](http://www.libe57.org/E57_EXT_surface_normals.txt) extension.
|
||||
class E57_DLL Writer
|
||||
{
|
||||
public:
|
||||
//! @brief This function is the constructor for the writer class
|
||||
//! @param [in] filePath file path to E57 file
|
||||
//! @param [in] coordinateMetaData Information describing the Coordinate Reference System to be used for the file
|
||||
Writer( const ustring &filePath, const ustring &coordinateMetaData = {} );
|
||||
/// @brief Writer constructor
|
||||
/// @param [in] filePath Path to E57 file
|
||||
/// @param [in] options Options to be used for the file
|
||||
Writer( const ustring &filePath, const WriterOptions &options );
|
||||
|
||||
//! @brief This function returns true if the file is open
|
||||
/// @brief Writer constructor (deprecated)
|
||||
/// @param [in] filePath Path to E57 file
|
||||
/// @param [in] coordinateMetadata Information describing the Coordinate Reference System to
|
||||
/// be used for the file
|
||||
/// @deprecated Will be removed in 4.0. Use Writer( const ustring &filePath, const
|
||||
/// WriterOptions &options ) instead.
|
||||
[[deprecated(
|
||||
"Will be removed in 4.0. Use Writer( ustring, WriterOptions )." )]] // TODO Remove in 4.0
|
||||
explicit Writer( const ustring &filePath, const ustring &coordinateMetadata = {} );
|
||||
|
||||
/// @brief Returns true if the file is open
|
||||
bool IsOpen() const;
|
||||
|
||||
//! @brief This function closes the file
|
||||
/// @brief Closes the file
|
||||
bool Close();
|
||||
|
||||
//! @name Image2D
|
||||
//!@{
|
||||
/// @name Image2D
|
||||
///@{
|
||||
|
||||
//! @brief This function writes a new Image2D header
|
||||
//! @details The user needs to config a Image2D structure with all the camera information before making this call.
|
||||
//! @param [in,out] image2DHeader header metadata
|
||||
//! @return Returns the image2D index
|
||||
/// @brief This function writes the Image2D data to the file
|
||||
/// @note @p image2DHeader may be modified (adding a guid or adding missing, required fields).
|
||||
/// @param [in,out] image2DHeader header metadata
|
||||
/// @param [in] imageType identifies the image format
|
||||
/// @param [in] imageProjection identifies the projection
|
||||
/// @param [in] startPos position in the block to start writing
|
||||
/// @param [in] buffer pointer the data buffer
|
||||
/// @param [in] byteCount buffer size
|
||||
/// @return Returns the number of bytes written
|
||||
int64_t WriteImage2DData( Image2D &image2DHeader, Image2DType imageType,
|
||||
Image2DProjection imageProjection, int64_t startPos, void *buffer,
|
||||
int64_t byteCount );
|
||||
|
||||
/// @brief Writes a new Image2D header
|
||||
/// @details The user needs to config a Image2D structure with all the camera information
|
||||
/// before making this call.
|
||||
/// @param [in,out] image2DHeader header metadata
|
||||
/// @return Returns the image2D index
|
||||
int64_t NewImage2D( Image2D &image2DHeader );
|
||||
|
||||
//! @brief This function writes the actual image data
|
||||
//! @param [in] imageIndex picture block index given by the NewImage2D
|
||||
//! @param [in] imageType identifies the image format desired.
|
||||
//! @param [in] imageProjection identifies the projection desired.
|
||||
//! @param [in] buffer pointer the buffer
|
||||
//! @param [in] start position in the block to start writing
|
||||
//! @param [in] count size of desired chuck or buffer size
|
||||
//! @return Returns the number of bytes written
|
||||
int64_t WriteImage2DData( int64_t imageIndex, Image2DType imageType, Image2DProjection imageProjection,
|
||||
void *buffer, int64_t start, int64_t count );
|
||||
/// @brief Writes the actual image data
|
||||
/// @param [in] imageIndex picture block index given by the NewImage2D
|
||||
/// @param [in] imageType identifies the image format desired.
|
||||
/// @param [in] imageProjection identifies the projection desired.
|
||||
/// @param [in] buffer pointer the buffer
|
||||
/// @param [in] start position in the block to start writing
|
||||
/// @param [in] count size of desired chunk or buffer size
|
||||
/// @return Returns the number of bytes written
|
||||
int64_t WriteImage2DData( int64_t imageIndex, Image2DType imageType,
|
||||
Image2DProjection imageProjection, void *buffer, int64_t start,
|
||||
int64_t count );
|
||||
|
||||
//!@}
|
||||
///@}
|
||||
|
||||
//! @name Data3D
|
||||
//!@{
|
||||
/// @name Data3D
|
||||
///@{
|
||||
|
||||
//! @brief This function writes new Data3D header
|
||||
//! @details The user needs to config a Data3D structure with all the scanning information before making this
|
||||
//! call.
|
||||
//! @param [in,out] data3DHeader scan metadata
|
||||
//! @return Returns the index of the new scan's data3D block.
|
||||
/// @brief This function writes the Data3D data to the file
|
||||
/// @details The user needs to config a Data3D structure with all the scanning information
|
||||
/// before making this call.
|
||||
/// @note @p data3DHeader may be modified (adding a guid or adding missing, required fields).
|
||||
/// @param [in,out] data3DHeader metadata about what is included in the buffers
|
||||
/// @param [in] buffers pointers to user-provided buffers containing the actual data
|
||||
/// @return Returns the index of the new scan's data3D block.
|
||||
int64_t WriteData3DData( Data3D &data3DHeader, const Data3DPointsFloat &buffers );
|
||||
|
||||
/// @overload
|
||||
int64_t WriteData3DData( Data3D &data3DHeader, const Data3DPointsDouble &buffers );
|
||||
|
||||
/// @brief Writes a new Data3D header
|
||||
/// @details The user needs to config a Data3D structure with all the scanning information
|
||||
/// before making this call.
|
||||
/// @param [in,out] data3DHeader scan metadata
|
||||
/// @return Returns the index of the new scan's data3D block.
|
||||
int64_t NewData3D( Data3D &data3DHeader );
|
||||
|
||||
//! @brief This function setups a writer to write the actual scan data
|
||||
//! @param [in] dataIndex index returned by NewData3D
|
||||
//! @param [in] pointCount Number of points to write (number of elements in each of the buffers)
|
||||
//! @param [in] buffers pointers to user-provided buffers
|
||||
//! @return returns a vector writer setup to write the selected scan data
|
||||
/// @brief Sets up a writer to write the actual scan data
|
||||
/// @param [in] dataIndex index returned by NewData3D
|
||||
/// @param [in] pointCount Number of points to write (number of elements in each of the
|
||||
/// buffers)
|
||||
/// @param [in] buffers pointers to user-provided buffers
|
||||
/// @return returns a vector writer setup to write the selected scan data
|
||||
CompressedVectorWriter SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsData &buffers );
|
||||
const Data3DPointsFloat &buffers );
|
||||
|
||||
//! @brief This function setups a writer to write the actual scan data
|
||||
//! @param [in] dataIndex index returned by NewData3D
|
||||
//! @param [in] pointCount Number of points to write (number of elements in each of the buffers)
|
||||
//! @param [in] buffers pointers to user-provided buffers
|
||||
//! @return returns a vector writer setup to write the selected scan data
|
||||
/// @overload
|
||||
CompressedVectorWriter SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsData_d &buffers );
|
||||
const Data3DPointsDouble &buffers );
|
||||
|
||||
//! @brief This function writes out the group data
|
||||
//! @param [in] dataIndex data block index given by the NewData3D
|
||||
//! @param [in] groupCount size of each of the buffers given
|
||||
//! @param [in] buffer of idElementValue index for this group
|
||||
//! @param [in] startPointIndex buffer with starting indices in to the "points" data vector for the groups
|
||||
//! @param [in] pointCount buffer with sizes of the groups given
|
||||
//! @return Return true if successful, false otherwise
|
||||
bool WriteData3DGroupsData( int64_t dataIndex, int64_t groupCount, int64_t *idElementValue,
|
||||
/// @brief Writes out the group data
|
||||
/// @param [in] dataIndex data block index given by the NewData3D
|
||||
/// @param [in] groupCount size of each of the buffers given
|
||||
/// @param [in] idElementValue buffer with idElementValue indices for this group
|
||||
/// @param [in] startPointIndex buffer with starting indices in to the "points" data vector
|
||||
/// for the groups
|
||||
/// @param [in] pointCount buffer with sizes of the groups given
|
||||
/// @return Return true if successful, false otherwise
|
||||
bool WriteData3DGroupsData( int64_t dataIndex, size_t groupCount, int64_t *idElementValue,
|
||||
int64_t *startPointIndex, int64_t *pointCount );
|
||||
|
||||
//!@}
|
||||
///@}
|
||||
|
||||
//! @name Foundation API file information
|
||||
//!@{
|
||||
/// @name File information
|
||||
///@{
|
||||
|
||||
//! @brief This function returns the file raw E57Root Structure Node
|
||||
/// @brief Returns the file raw E57Root Structure Node
|
||||
StructureNode GetRawE57Root();
|
||||
//! @brief This function returns the raw Data3D Vector Node
|
||||
/// @brief Returns the raw Data3D Vector Node
|
||||
VectorNode GetRawData3D();
|
||||
//! @brief This function returns the raw Image2D Vector Node
|
||||
/// @brief Returns the raw Image2D Vector Node
|
||||
VectorNode GetRawImages2D();
|
||||
//! @brief This function returns the ram ImageFile Node which is need to add enhancements
|
||||
/// @brief Returns the ram ImageFile Node which is need to add enhancements
|
||||
ImageFile GetRawIMF();
|
||||
|
||||
//!@}
|
||||
///@}
|
||||
|
||||
//! @cond documentNonPublic The following isn't part of the API, and isn't
|
||||
//! documented.
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
protected:
|
||||
friend class WriterImpl;
|
||||
|
||||
E57_OBJECT_IMPLEMENTATION( Writer ) // Internal implementation details, not part of API, must be last in object
|
||||
//! @endcond
|
||||
E57_INTERNAL_ACCESS( Writer )
|
||||
|
||||
protected:
|
||||
std::shared_ptr<WriterImpl> impl_;
|
||||
/// @endcond
|
||||
}; // end Writer class
|
||||
|
||||
} // end namespace e57
|
||||
|
||||
72
src/3rdParty/libE57Format/include/E57Version.h
vendored
Normal file
72
src/3rdParty/libE57Format/include/E57Version.h
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
// Copyright © 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
/// @file E57Version.h ASTM & libE57Format version information.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "E57Export.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
namespace Version
|
||||
{
|
||||
/*!
|
||||
@brief Get the version of the ASTM E57 standard that libE57Format supports.
|
||||
|
||||
@returns The version as a string (e.g. "1.0")
|
||||
*/
|
||||
E57_DLL std::string astm();
|
||||
|
||||
/*!
|
||||
@brief Get the major version of the ASTM E57 standard that libE57Format supports.
|
||||
|
||||
@returns The major version
|
||||
*/
|
||||
E57_DLL uint32_t astmMajor();
|
||||
|
||||
/*!
|
||||
@brief Get the minor version of the ASTM E57 standard that libE57Format supports.
|
||||
|
||||
@returns The minor version
|
||||
*/
|
||||
E57_DLL uint32_t astmMinor();
|
||||
|
||||
/*!
|
||||
@brief Get the version of libE57Format library.
|
||||
|
||||
@returns The version as a string (e.g. "E57Format-3.0.0-x86_64-darwin-AppleClang140").
|
||||
*/
|
||||
E57_DLL std::string library();
|
||||
|
||||
/*!
|
||||
@brief Get the version of ASTM E57 standard that the API implementation supports, and library
|
||||
id string.
|
||||
|
||||
@param [out] astmMajor The major version number of the ASTM E57 standard supported.
|
||||
@param [out] astmMinor The minor version number of the ASTM E57 standard supported.
|
||||
@param [out] libraryId A string identifying the implementation of the API.
|
||||
|
||||
@details
|
||||
Since the E57 implementation may be dynamically linked underneath the API, the version string
|
||||
for the implementation and the ASTM version that it supports can't be determined at
|
||||
compile-time. This function returns these identifiers from the underlying implementation.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
*/
|
||||
E57_DLL void get( uint32_t &astmMajor, uint32_t &astmMinor, std::string &libraryId );
|
||||
}
|
||||
|
||||
namespace Utilities
|
||||
{
|
||||
/*!
|
||||
@copydetails Version::get()
|
||||
@deprecated Will be removed in 4.0. Use Version::get() or other functions in the Version
|
||||
namespace.
|
||||
*/
|
||||
[[deprecated( "Will be removed in 4.0. Use Version::get() or other functions in the Version "
|
||||
"namespace." )]] E57_DLL void
|
||||
getVersions( int &astmMajor, int &astmMinor, std::string &libraryId );
|
||||
}
|
||||
}
|
||||
16
src/3rdParty/libE57Format/src/ASTMVersion.h
vendored
Normal file
16
src/3rdParty/libE57Format/src/ASTMVersion.h
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
// Copyright © 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace e57
|
||||
{
|
||||
/// The file format major version number. The value shall be 1.
|
||||
/// @remark E57 Standard Table 1 - Format of the E57 File Header Section
|
||||
constexpr uint32_t E57_FORMAT_MAJOR = 1;
|
||||
|
||||
/// The file format minor version number. The value shall be 0.
|
||||
/// @remark E57 Standard Table 1 - Format of the E57 File Header Section
|
||||
constexpr uint32_t E57_FORMAT_MINOR = 0;
|
||||
}
|
||||
367
src/3rdParty/libE57Format/src/BlobNode.cpp
vendored
Normal file
367
src/3rdParty/libE57Format/src/BlobNode.cpp
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* BlobNode.cpp - implementation of public functions of the BlobNode class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file BlobNode.cpp
|
||||
|
||||
#include "BlobNodeImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether BlobNode class invariant is true
|
||||
@copydetails IntegerNode::checkInvariant()
|
||||
*/
|
||||
void BlobNode::checkInvariant( bool /*doRecurse*/, bool doUpcast ) const
|
||||
{
|
||||
// If destImageFile not open, can't test invariant (almost every call would throw)
|
||||
if ( !destImageFile().isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If requested, call Node::checkInvariant
|
||||
if ( doUpcast )
|
||||
{
|
||||
static_cast<Node>( *this ).checkInvariant( false, false );
|
||||
}
|
||||
|
||||
if ( byteCount() < 0 )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::BlobNode
|
||||
|
||||
@brief An E57 element encoding an fixed-length sequence of bytes with an opaque format.
|
||||
|
||||
@details
|
||||
A BlobNode is a terminal node (i.e. having no children) that holds an opaque, fixed-length sequence
|
||||
of bytes. The number of bytes in the BlobNode is declared at creation time. The content of the blob
|
||||
is stored within the E57 file in an efficient binary format (but not compressed). The BlobNode
|
||||
cannot grow after it is created. There is no ordering constraints on how content of a BlobNode may
|
||||
be accessed (i.e. it is random access). BlobNodes in an ImageFile opened for reading are read-only.
|
||||
|
||||
There are two categories of BlobNodes, distinguished by their usage: private BlobNodes and public
|
||||
BlobNodes. In a private BlobNode, the format of its content bytes is not published. This is useful
|
||||
for storing proprietary data that a writer does not wish to share with all readers. Rather than put
|
||||
this information in a separate file, the writer can embed the file inside the E57 file so it cannot
|
||||
be lost.
|
||||
|
||||
In a public BlobNode, the format is published or follows some industry standard format (e.g. JPEG).
|
||||
Rather than reinvent the wheel in applications that are already well-served by an existing format
|
||||
standard, an E57 file writer can just embed an existing file as an "attachment" in a BlobNode. The
|
||||
internal format of a public BlobNode is not enforced by the Foundation API. It is recommended that
|
||||
there be some mechanism for a reader to know ahead of time which format the BlobNode content adheres
|
||||
to (either specified by a document, or encoded by some scheme in the E57 Element tree).
|
||||
|
||||
The BlobNode is the one node type where the set-once policy is not strictly enforced. It is possible
|
||||
to write the same byte location in a BlobNode several times. However it is not recommended.
|
||||
|
||||
See Node class discussion for discussion of the common functions that StructureNode supports.
|
||||
|
||||
@section BlobNode_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or, can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude BlobNode.cpp
|
||||
@skip void BlobNode::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see Node
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Create an element for storing a sequence of bytes with an opaque format.
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
@param [in] byteCount The number of bytes reserved in the ImageFile for holding the blob.
|
||||
@details
|
||||
The BlobNode class corresponds to the ASTM E57 standard Blob element.
|
||||
|
||||
See the class discussion at bottom of BlobNode page for more details.
|
||||
|
||||
The E57 Foundation Implementation may pre-allocate disk space in the ImageFile to store the declared
|
||||
length of the blob. The disk must have enough free space to store @a byteCount bytes of data. The
|
||||
data of a newly created BlobNode is initialized to zero.
|
||||
|
||||
The @a destImageFile indicates which ImageFile the BlobNode will eventually be attached to. A node
|
||||
is attached to an ImageFile by adding it underneath the predefined root of the ImageFile (gotten
|
||||
from ImageFile::root). It is not an error to fail to attach the BlobNode to the @a destImageFile. It
|
||||
is an error to attempt to attach the BlobNode to a different ImageFile.
|
||||
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable()
|
||||
must be true).
|
||||
@pre byteCount >= 0
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node, BlobNode::read, BlobNode::write
|
||||
*/
|
||||
BlobNode::BlobNode( const ImageFile &destImageFile, int64_t byteCount ) :
|
||||
impl_( new BlobNodeImpl( destImageFile.impl(), byteCount ) )
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is this a root node.
|
||||
@copydetails Node::isRoot()
|
||||
*/
|
||||
bool BlobNode::isRoot() const
|
||||
{
|
||||
return impl_->isRoot();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return parent of node, or self if a root node.
|
||||
@copydetails Node::parent()
|
||||
*/
|
||||
Node BlobNode::parent() const
|
||||
{
|
||||
return Node( impl_->parent() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get absolute pathname of node.
|
||||
@copydetails Node::pathName()
|
||||
*/
|
||||
ustring BlobNode::pathName() const
|
||||
{
|
||||
return impl_->pathName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get elementName string, that identifies the node in its parent.
|
||||
@copydetails Node::elementName()
|
||||
*/
|
||||
ustring BlobNode::elementName() const
|
||||
{
|
||||
return impl_->elementName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the ImageFile that was declared as the destination for the node when it was created.
|
||||
@copydetails Node::destImageFile()
|
||||
*/
|
||||
ImageFile BlobNode::destImageFile() const
|
||||
{
|
||||
return ImageFile( impl_->destImageFile() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Has node been attached into the tree of an ImageFile.
|
||||
@copydetails Node::isAttached()
|
||||
*/
|
||||
bool BlobNode::isAttached() const
|
||||
{
|
||||
return impl_->isAttached();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get size of blob declared when it was created.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The declared size of the blob when it was created.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see BlobNode::read, BlobNode::write
|
||||
*/
|
||||
int64_t BlobNode::byteCount() const
|
||||
{
|
||||
return impl_->byteCount();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Read a buffer of bytes from a blob.
|
||||
|
||||
@param [in] buf A memory buffer to store bytes read from the blob.
|
||||
@param [in] start The index of the first byte in blob to read.
|
||||
@param [in] count The number of bytes to read.
|
||||
|
||||
@details
|
||||
The memory buffer @a buf must be able to store at least @a count bytes.
|
||||
|
||||
The data is stored in a binary section of the ImageFile with checksum protection, so undetected
|
||||
corruption is very unlikely. It is an error to attempt to read outside the declared size of the
|
||||
Blob. The format of the data read is opaque (unspecified by the ASTM E57 data format standard).
|
||||
Since @a buf is a byte buffer, byte ordering is irrelevant (it will come out in the same order that
|
||||
it went in). There is no constraint on the ordering of reads. Any part of the Blob data can be read
|
||||
zero or more times.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@pre buf != NULL
|
||||
@pre 0 <= @a start < byteCount()
|
||||
@pre 0 <= count
|
||||
@pre (@a start + @a count) < byteCount()
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorSeekFailed
|
||||
@throw ::ErrorReadFailed
|
||||
@throw ::ErrorBadChecksum
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see BlobNode::byteCount, BlobNode::write
|
||||
*/
|
||||
void BlobNode::read( uint8_t *buf, int64_t start, size_t count )
|
||||
{
|
||||
impl_->read( buf, start, count );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Write a buffer of bytes to a blob.
|
||||
|
||||
@param [in] buf A memory buffer of bytes to write to the blob.
|
||||
@param [in] start The index of the first byte in blob to write to.
|
||||
@param [in] count The number of bytes to write.
|
||||
|
||||
@details
|
||||
The memory buffer @a buf must store at least @a count bytes.
|
||||
|
||||
The data is stored in a binary section of the ImageFile with checksum protection, so undetected
|
||||
corruption is very unlikely. It is an error to attempt to write outside the declared size of the
|
||||
Blob. The format of the data written is opaque (unspecified by the ASTM E57 data format standard).
|
||||
Since @a buf is a byte buffer, byte ordering is irrelevant (it will come out in the same order that
|
||||
it went in). There is no constraint on the ordering of writes. It is not an error to write a portion
|
||||
of the BlobNode data more than once, or not at all. Initially all the BlobNode data is zero, so if a
|
||||
portion is not written, it will remain zero. The BlobNode is one of the two node types that must be
|
||||
attached to the root of a write mode ImageFile before write operations can be performed (the other
|
||||
type is CompressedVectorNode).
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@pre The associated destImageFile must have been opened in write mode (i.e.
|
||||
destImageFile().isWritable()).
|
||||
@pre The BlobNode must be attached to an ImageFile (i.e. isAttached()).
|
||||
@pre buf != NULL
|
||||
@pre 0 <= @a start < byteCount()
|
||||
@pre 0 <= count
|
||||
@pre (@a start + @a count) < byteCount()
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorNodeUnattached
|
||||
@throw ::ErrorSeekFailed
|
||||
@throw ::ErrorReadFailed
|
||||
@throw ::ErrorWriteFailed
|
||||
@throw ::ErrorBadChecksum
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see BlobNode::byteCount, BlobNode::read
|
||||
*/
|
||||
void BlobNode::write( uint8_t *buf, int64_t start, size_t count )
|
||||
{
|
||||
impl_->write( buf, start, count );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void BlobNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void BlobNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Upcast a BlobNode handle to a generic Node handle.
|
||||
|
||||
@details
|
||||
An upcast is always safe, and the compiler can automatically insert it for initializations of Node
|
||||
variables and Node function arguments.
|
||||
|
||||
@return A smart Node handle referencing the underlying object.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see Explanation in Node, Node::type(), BlobNode(const Node&)
|
||||
*/
|
||||
BlobNode::operator Node() const
|
||||
{
|
||||
// Upcast from shared_ptr<StringNodeImpl> to SharedNodeImplPtr and construct
|
||||
// a Node object
|
||||
return Node( impl_ );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Downcast a generic Node handle to a BlobNode handle.
|
||||
|
||||
@param [in] n The generic handle to downcast.
|
||||
|
||||
@details
|
||||
The handle @a n must be for an underlying BlobNode, otherwise an exception is thrown. In designs
|
||||
that need to avoid the exception, use Node::type() to determine the actual type of the @a n before
|
||||
downcasting. This function must be explicitly called (c++ compiler cannot insert it automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
|
||||
@see Node::type(), BlobNode::operator Node()
|
||||
*/
|
||||
BlobNode::BlobNode( const Node &n )
|
||||
{
|
||||
if ( n.type() != TypeBlob )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadNodeDowncast, "nodeType=" + toString( n.type() ) );
|
||||
}
|
||||
|
||||
// Set our shared_ptr to the downcast shared_ptr
|
||||
impl_ = std::static_pointer_cast<BlobNodeImpl>( n.impl() );
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
BlobNode::BlobNode( const ImageFile &destImageFile, int64_t fileOffset, int64_t length ) :
|
||||
impl_( new BlobNodeImpl( destImageFile.impl(), fileOffset, length ) )
|
||||
{
|
||||
}
|
||||
|
||||
BlobNode::BlobNode( std::shared_ptr<BlobNodeImpl> ni ) : impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
81
src/3rdParty/libE57Format/src/BlobNodeImpl.cpp
vendored
81
src/3rdParty/libE57Format/src/BlobNodeImpl.cpp
vendored
@@ -29,19 +29,21 @@
|
||||
#include "CheckedFile.h"
|
||||
#include "ImageFileImpl.h"
|
||||
#include "SectionHeaders.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
BlobNodeImpl::BlobNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t byteCount ) : NodeImpl( destImageFile )
|
||||
BlobNodeImpl::BlobNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t byteCount ) :
|
||||
NodeImpl( destImageFile )
|
||||
{
|
||||
// don't checkImageFileOpen, NodeImpl() will do it
|
||||
|
||||
ImageFileImplSharedPtr imf( destImageFile );
|
||||
|
||||
/// This what caller thinks blob length is
|
||||
// This what caller thinks blob length is
|
||||
blobLogicalLength_ = byteCount;
|
||||
|
||||
/// Round segment length up to multiple of 4 bytes
|
||||
// Round segment length up to multiple of 4 bytes
|
||||
binarySectionLogicalLength_ = sizeof( BlobSectionHeader ) + blobLogicalLength_;
|
||||
unsigned remainder = binarySectionLogicalLength_ % 4;
|
||||
if ( remainder > 0 )
|
||||
@@ -49,32 +51,32 @@ namespace e57
|
||||
binarySectionLogicalLength_ += 4 - remainder;
|
||||
}
|
||||
|
||||
/// Reserve space for blob in file, extend with zeros since writes will
|
||||
/// happen at later time by caller
|
||||
// Reserve space for blob in file, extend with zeros since writes will
|
||||
// happen at later time by caller
|
||||
binarySectionLogicalStart_ = imf->allocateSpace( binarySectionLogicalLength_, true );
|
||||
|
||||
/// Prepare BlobSectionHeader
|
||||
// Prepare BlobSectionHeader
|
||||
BlobSectionHeader header;
|
||||
header.sectionLogicalLength = binarySectionLogicalLength_;
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
header.dump(); //???
|
||||
#endif
|
||||
|
||||
/// Write header at beginning of section
|
||||
// Write header at beginning of section
|
||||
imf->file_->seek( binarySectionLogicalStart_ );
|
||||
imf->file_->write( reinterpret_cast<char *>( &header ), sizeof( header ) );
|
||||
}
|
||||
|
||||
BlobNodeImpl::BlobNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t fileOffset, int64_t length ) :
|
||||
NodeImpl( destImageFile )
|
||||
BlobNodeImpl::BlobNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t fileOffset,
|
||||
int64_t length ) : NodeImpl( destImageFile )
|
||||
{
|
||||
/// Init blob object that already exists in E57 file currently reading.
|
||||
// Init blob object that already exists in E57 file currently reading.
|
||||
|
||||
// don't checkImageFileOpen, NodeImpl() will do it
|
||||
|
||||
ImageFileImplSharedPtr imf( destImageFile );
|
||||
|
||||
/// Init state from values read from XML
|
||||
// Init state from values read from XML
|
||||
blobLogicalLength_ = length;
|
||||
binarySectionLogicalStart_ = imf->file_->physicalToLogical( fileOffset );
|
||||
binarySectionLogicalLength_ = sizeof( BlobSectionHeader ) + blobLogicalLength_;
|
||||
@@ -84,24 +86,24 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen, NodeImpl() will do it
|
||||
|
||||
/// Same node type?
|
||||
if ( ni->type() != E57_BLOB )
|
||||
// Same node type?
|
||||
if ( ni->type() != TypeBlob )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// Downcast to shared_ptr<BlobNodeImpl>
|
||||
// Downcast to shared_ptr<BlobNodeImpl>
|
||||
std::shared_ptr<BlobNodeImpl> bi( std::static_pointer_cast<BlobNodeImpl>( ni ) );
|
||||
|
||||
/// blob lengths must match
|
||||
// blob lengths must match
|
||||
if ( blobLogicalLength_ != bi->blobLogicalLength_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// ignore blob contents, doesn't have to match
|
||||
// ignore blob contents, doesn't have to match
|
||||
|
||||
/// Types match
|
||||
// Types match
|
||||
return ( true );
|
||||
}
|
||||
|
||||
@@ -109,7 +111,7 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen, NodeImpl() will do it
|
||||
|
||||
/// We have no sub-structure, so if path not empty return false
|
||||
// We have no sub-structure, so if path not empty return false
|
||||
return pathName.empty();
|
||||
}
|
||||
|
||||
@@ -126,9 +128,10 @@ namespace e57
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
if ( static_cast<uint64_t>( start ) + count > blobLogicalLength_ )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT,
|
||||
"this->pathName=" + this->pathName() + " start=" + toString( start ) +
|
||||
" count=" + toString( count ) + " length=" + toString( blobLogicalLength_ ) );
|
||||
throw E57_EXCEPTION2( ErrorBadAPIArgument,
|
||||
"this->pathName=" + this->pathName() +
|
||||
" start=" + toString( start ) + " count=" + toString( count ) +
|
||||
" length=" + toString( blobLogicalLength_ ) );
|
||||
}
|
||||
|
||||
ImageFileImplSharedPtr imf( destImageFile_ );
|
||||
@@ -146,18 +149,19 @@ namespace e57
|
||||
|
||||
if ( !destImageFile->isWriter() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_FILE_IS_READ_ONLY, "fileName=" + destImageFile->fileName() );
|
||||
throw E57_EXCEPTION2( ErrorFileReadOnly, "fileName=" + destImageFile->fileName() );
|
||||
}
|
||||
if ( !isAttached() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_NODE_UNATTACHED, "fileName=" + destImageFile->fileName() );
|
||||
throw E57_EXCEPTION2( ErrorNodeUnattached, "fileName=" + destImageFile->fileName() );
|
||||
}
|
||||
|
||||
if ( static_cast<uint64_t>( start ) + count > blobLogicalLength_ )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT,
|
||||
"this->pathName=" + this->pathName() + " start=" + toString( start ) +
|
||||
" count=" + toString( count ) + " length=" + toString( blobLogicalLength_ ) );
|
||||
throw E57_EXCEPTION2( ErrorBadAPIArgument,
|
||||
"this->pathName=" + this->pathName() +
|
||||
" start=" + toString( start ) + " count=" + toString( count ) +
|
||||
" length=" + toString( blobLogicalLength_ ) );
|
||||
}
|
||||
|
||||
ImageFileImplSharedPtr imf( destImageFile_ );
|
||||
@@ -170,11 +174,11 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// We are a leaf node, so verify that we are listed in set. ???true for
|
||||
/// blobs? what exception get if try blob in compressedvector?
|
||||
// We are a leaf node, so verify that we are listed in set. ???true for
|
||||
// blobs? what exception get if try blob in compressedvector?
|
||||
if ( pathNames.find( relativePathName( origin ) ) == pathNames.end() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_NO_BUFFER_FOR_ELEMENT, "this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorNoBufferForElement, "this->pathName=" + this->pathName() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +188,7 @@ namespace e57
|
||||
// don't checkImageFileOpen
|
||||
|
||||
ustring fieldName;
|
||||
if ( forcedFieldName )
|
||||
if ( forcedFieldName != nullptr )
|
||||
{
|
||||
fieldName = forcedFieldName;
|
||||
}
|
||||
@@ -197,20 +201,21 @@ namespace e57
|
||||
//??? Type --> type
|
||||
//??? need to have length?, check same as in section header?
|
||||
uint64_t physicalOffset = cf.logicalToPhysical( binarySectionLogicalStart_ );
|
||||
cf << space( indent ) << "<" << fieldName << " type=\"Blob\" fileOffset=\"" << physicalOffset << "\" length=\""
|
||||
<< blobLogicalLength_ << "\"/>\n";
|
||||
cf << space( indent ) << "<" << fieldName << " type=\"Blob\" fileOffset=\"" << physicalOffset
|
||||
<< "\" length=\"" << blobLogicalLength_ << "\"/>\n";
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void BlobNodeImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
os << space( indent ) << "type: Blob"
|
||||
<< " (" << type() << ")" << std::endl;
|
||||
os << space( indent ) << "type: Blob" << " (" << type() << ")" << std::endl;
|
||||
NodeImpl::dump( indent, os );
|
||||
os << space( indent ) << "blobLogicalLength_: " << blobLogicalLength_ << std::endl;
|
||||
os << space( indent ) << "binarySectionLogicalStart: " << binarySectionLogicalStart_ << std::endl;
|
||||
os << space( indent ) << "binarySectionLogicalLength: " << binarySectionLogicalLength_ << std::endl;
|
||||
os << space( indent ) << "binarySectionLogicalStart: " << binarySectionLogicalStart_
|
||||
<< std::endl;
|
||||
os << space( indent ) << "binarySectionLogicalLength: " << binarySectionLogicalLength_
|
||||
<< std::endl;
|
||||
// size_t i;
|
||||
// for (i = 0; i < blobLogicalLength_ && i < 10; i++) {
|
||||
// uint8_t b;
|
||||
|
||||
5
src/3rdParty/libE57Format/src/BlobNodeImpl.h
vendored
5
src/3rdParty/libE57Format/src/BlobNodeImpl.h
vendored
@@ -39,8 +39,9 @@ namespace e57
|
||||
|
||||
NodeType type() const override
|
||||
{
|
||||
return E57_BLOB;
|
||||
return TypeBlob;
|
||||
}
|
||||
|
||||
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
|
||||
bool isDefined( const ustring &pathName ) override;
|
||||
|
||||
@@ -53,7 +54,7 @@ namespace e57
|
||||
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
|
||||
const char *forcedFieldName = nullptr ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
|
||||
121
src/3rdParty/libE57Format/src/CMakeLists.txt
vendored
121
src/3rdParty/libE57Format/src/CMakeLists.txt
vendored
@@ -1,60 +1,75 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# Copyright 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
target_sources( E57Format
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/BlobNodeImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/BlobNodeImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/CheckedFile.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/CheckedFile.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/Common.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/Common.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/CompressedVectorNodeImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/CompressedVectorNodeImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/CompressedVectorReaderImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/CompressedVectorReaderImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/CompressedVectorWriterImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/CompressedVectorWriterImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/DecodeChannel.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/DecodeChannel.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/Decoder.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/Decoder.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/Encoder.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/Encoder.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/FloatNodeImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/FloatNodeImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/IntegerNodeImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/IntegerNodeImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/NodeImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/NodeImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/Packet.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/Packet.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/ImageFileImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/ImageFileImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/ReaderImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/ReaderImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/ScaledIntegerNodeImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/ScaledIntegerNodeImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/SectionHeaders.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/SectionHeaders.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/SourceDestBufferImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/SourceDestBufferImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/StringNodeImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/StringNodeImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/StructureNodeImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/StructureNodeImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/VectorNodeImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/VectorNodeImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/WriterImpl.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/WriterImpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57Exception.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57Format.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57SimpleData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57SimpleReader.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57SimpleWriter.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57Version.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57XmlParser.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/E57XmlParser.h
|
||||
ASTMVersion.h
|
||||
BlobNode.cpp
|
||||
BlobNodeImpl.h
|
||||
BlobNodeImpl.cpp
|
||||
CheckedFile.h
|
||||
CheckedFile.cpp
|
||||
Common.h
|
||||
Common.cpp
|
||||
CompressedVectorNode.cpp
|
||||
CompressedVectorNodeImpl.h
|
||||
CompressedVectorNodeImpl.cpp
|
||||
CompressedVectorReader.cpp
|
||||
CompressedVectorReaderImpl.h
|
||||
CompressedVectorReaderImpl.cpp
|
||||
CompressedVectorWriter.cpp
|
||||
CompressedVectorWriterImpl.h
|
||||
CompressedVectorWriterImpl.cpp
|
||||
DecodeChannel.h
|
||||
DecodeChannel.cpp
|
||||
Decoder.h
|
||||
Decoder.cpp
|
||||
Encoder.h
|
||||
Encoder.cpp
|
||||
FloatNode.cpp
|
||||
FloatNodeImpl.h
|
||||
FloatNodeImpl.cpp
|
||||
ImageFile.cpp
|
||||
ImageFileImpl.h
|
||||
ImageFileImpl.cpp
|
||||
IntegerNode.cpp
|
||||
IntegerNodeImpl.h
|
||||
IntegerNodeImpl.cpp
|
||||
Node.cpp
|
||||
NodeImpl.h
|
||||
NodeImpl.cpp
|
||||
Packet.h
|
||||
Packet.cpp
|
||||
ReaderImpl.h
|
||||
ReaderImpl.cpp
|
||||
ScaledIntegerNode.cpp
|
||||
ScaledIntegerNodeImpl.h
|
||||
ScaledIntegerNodeImpl.cpp
|
||||
SectionHeaders.h
|
||||
SectionHeaders.cpp
|
||||
SourceDestBuffer.cpp
|
||||
SourceDestBufferImpl.h
|
||||
SourceDestBufferImpl.cpp
|
||||
StringNode.cpp
|
||||
StringFunctions.h
|
||||
StringFunctions.cpp
|
||||
StringNodeImpl.h
|
||||
StringNodeImpl.cpp
|
||||
StructureNode.cpp
|
||||
StructureNodeImpl.h
|
||||
StructureNodeImpl.cpp
|
||||
VectorNode.cpp
|
||||
VectorNodeImpl.h
|
||||
VectorNodeImpl.cpp
|
||||
WriterImpl.h
|
||||
WriterImpl.cpp
|
||||
E57Exception.cpp
|
||||
E57SimpleData.cpp
|
||||
E57SimpleReader.cpp
|
||||
E57SimpleWriter.cpp
|
||||
E57Version.cpp
|
||||
E57XmlParser.cpp
|
||||
E57XmlParser.h
|
||||
)
|
||||
|
||||
target_include_directories( E57Format
|
||||
|
||||
1585
src/3rdParty/libE57Format/src/CheckedFile.cpp
vendored
1585
src/3rdParty/libE57Format/src/CheckedFile.cpp
vendored
File diff suppressed because it is too large
Load Diff
257
src/3rdParty/libE57Format/src/CheckedFile.h
vendored
257
src/3rdParty/libE57Format/src/CheckedFile.h
vendored
@@ -1,128 +1,129 @@
|
||||
/*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
/// Tool class to read buffer efficiently without
|
||||
/// multiplying copy operations.
|
||||
///
|
||||
/// WARNING: pointer input is handled by user!
|
||||
class BufferView;
|
||||
|
||||
class CheckedFile
|
||||
{
|
||||
public:
|
||||
static constexpr size_t physicalPageSizeLog2 = 10; // physical page size is 2 raised to this power
|
||||
static constexpr size_t physicalPageSize = 1 << physicalPageSizeLog2;
|
||||
static constexpr uint64_t physicalPageSizeMask = physicalPageSize - 1;
|
||||
static constexpr size_t logicalPageSize = physicalPageSize - 4;
|
||||
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
ReadOnly,
|
||||
WriteCreate,
|
||||
WriteExisting
|
||||
};
|
||||
|
||||
enum OffsetMode
|
||||
{
|
||||
Logical,
|
||||
Physical
|
||||
};
|
||||
|
||||
CheckedFile( const e57::ustring &fileName, Mode mode, ReadChecksumPolicy policy );
|
||||
CheckedFile( const char *input, uint64_t size, ReadChecksumPolicy policy );
|
||||
~CheckedFile();
|
||||
|
||||
void read( char *buf, size_t nRead, size_t bufSize = 0 );
|
||||
void write( const char *buf, size_t nWrite );
|
||||
CheckedFile &operator<<( const e57::ustring &s );
|
||||
CheckedFile &operator<<( int64_t i );
|
||||
CheckedFile &operator<<( uint64_t i );
|
||||
CheckedFile &operator<<( float f );
|
||||
CheckedFile &operator<<( double d );
|
||||
void seek( uint64_t offset, OffsetMode omode = Logical );
|
||||
uint64_t position( OffsetMode omode = Logical );
|
||||
uint64_t length( OffsetMode omode = Logical );
|
||||
void extend( uint64_t newLength, OffsetMode omode = Logical );
|
||||
e57::ustring fileName() const
|
||||
{
|
||||
return fileName_;
|
||||
}
|
||||
void close();
|
||||
void unlink();
|
||||
|
||||
static inline uint64_t logicalToPhysical( uint64_t logicalOffset );
|
||||
static inline uint64_t physicalToLogical( uint64_t physicalOffset );
|
||||
|
||||
private:
|
||||
uint32_t checksum( char *buf, size_t size ) const;
|
||||
void verifyChecksum( char *page_buffer, size_t page );
|
||||
|
||||
template <class FTYPE> CheckedFile &writeFloatingPoint( FTYPE value, int precision );
|
||||
|
||||
void getCurrentPageAndOffset( uint64_t &page, size_t &pageOffset, OffsetMode omode = Logical );
|
||||
void readPhysicalPage( char *page_buffer, uint64_t page );
|
||||
void writePhysicalPage( char *page_buffer, uint64_t page );
|
||||
int open64( const e57::ustring &fileName, int flags, int mode );
|
||||
uint64_t lseek64( int64_t offset, int whence );
|
||||
|
||||
e57::ustring fileName_;
|
||||
uint64_t logicalLength_ = 0;
|
||||
uint64_t physicalLength_ = 0;
|
||||
|
||||
ReadChecksumPolicy checkSumPolicy_ = CHECKSUM_POLICY_ALL;
|
||||
|
||||
int fd_ = -1;
|
||||
BufferView *bufView_ = nullptr;
|
||||
bool readOnly_ = false;
|
||||
};
|
||||
|
||||
inline uint64_t CheckedFile::logicalToPhysical( uint64_t logicalOffset )
|
||||
{
|
||||
const uint64_t page = logicalOffset / logicalPageSize;
|
||||
const uint64_t remainder = logicalOffset - page * logicalPageSize;
|
||||
|
||||
return page * physicalPageSize + remainder;
|
||||
}
|
||||
|
||||
inline uint64_t CheckedFile::physicalToLogical( uint64_t physicalOffset )
|
||||
{
|
||||
const uint64_t page = physicalOffset >> physicalPageSizeLog2;
|
||||
const size_t remainder = static_cast<size_t>( physicalOffset & physicalPageSizeMask );
|
||||
|
||||
return page * logicalPageSize + std::min( remainder, logicalPageSize );
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
// Tool class to read buffer efficiently without
|
||||
// multiplying copy operations.
|
||||
//
|
||||
// WARNING: pointer input is handled by user!
|
||||
class BufferView;
|
||||
|
||||
class CheckedFile
|
||||
{
|
||||
public:
|
||||
// physical page size is 2 raised to this power
|
||||
static constexpr size_t physicalPageSizeLog2 = 10;
|
||||
static constexpr size_t physicalPageSize = 1 << physicalPageSizeLog2;
|
||||
static constexpr uint64_t physicalPageSizeMask = physicalPageSize - 1;
|
||||
static constexpr size_t logicalPageSize = physicalPageSize - 4;
|
||||
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
Read,
|
||||
Write,
|
||||
};
|
||||
|
||||
enum OffsetMode
|
||||
{
|
||||
Logical,
|
||||
Physical
|
||||
};
|
||||
|
||||
CheckedFile( const e57::ustring &fileName, Mode mode, ReadChecksumPolicy policy );
|
||||
CheckedFile( const char *input, uint64_t size, ReadChecksumPolicy policy );
|
||||
~CheckedFile();
|
||||
|
||||
void read( char *buf, size_t nRead, size_t bufSize = 0 );
|
||||
void write( const char *buf, size_t nWrite );
|
||||
CheckedFile &operator<<( const e57::ustring &s );
|
||||
CheckedFile &operator<<( int64_t i );
|
||||
CheckedFile &operator<<( uint64_t i );
|
||||
CheckedFile &operator<<( float f );
|
||||
CheckedFile &operator<<( double d );
|
||||
void seek( uint64_t offset, OffsetMode omode = Logical );
|
||||
uint64_t position( OffsetMode omode = Logical );
|
||||
uint64_t length( OffsetMode omode = Logical );
|
||||
void extend( uint64_t newLength, OffsetMode omode = Logical );
|
||||
|
||||
e57::ustring fileName() const
|
||||
{
|
||||
return fileName_;
|
||||
}
|
||||
|
||||
void close();
|
||||
void unlink();
|
||||
|
||||
static inline uint64_t logicalToPhysical( uint64_t logicalOffset );
|
||||
static inline uint64_t physicalToLogical( uint64_t physicalOffset );
|
||||
|
||||
private:
|
||||
void verifyChecksum( char *page_buffer, uint64_t page );
|
||||
|
||||
template <class FTYPE> CheckedFile &writeFloatingPoint( FTYPE value, int precision );
|
||||
|
||||
void getCurrentPageAndOffset( uint64_t &page, size_t &pageOffset,
|
||||
OffsetMode omode = Logical );
|
||||
void readPhysicalPage( char *page_buffer, uint64_t page );
|
||||
void writePhysicalPage( char *page_buffer, uint64_t page );
|
||||
int open64( const e57::ustring &fileName, int flags, int mode );
|
||||
uint64_t lseek64( int64_t offset, int whence );
|
||||
|
||||
e57::ustring fileName_;
|
||||
uint64_t logicalLength_ = 0;
|
||||
uint64_t physicalLength_ = 0;
|
||||
|
||||
ReadChecksumPolicy checkSumPolicy_ = ChecksumPolicy::ChecksumAll;
|
||||
|
||||
int fd_ = -1;
|
||||
BufferView *bufView_ = nullptr;
|
||||
bool readOnly_ = false;
|
||||
};
|
||||
|
||||
inline uint64_t CheckedFile::logicalToPhysical( uint64_t logicalOffset )
|
||||
{
|
||||
const uint64_t page = logicalOffset / logicalPageSize;
|
||||
const uint64_t remainder = logicalOffset - page * logicalPageSize;
|
||||
|
||||
return page * physicalPageSize + remainder;
|
||||
}
|
||||
|
||||
inline uint64_t CheckedFile::physicalToLogical( uint64_t physicalOffset )
|
||||
{
|
||||
const uint64_t page = physicalOffset >> physicalPageSizeLog2;
|
||||
const auto remainder = static_cast<size_t>( physicalOffset & physicalPageSizeMask );
|
||||
|
||||
return page * logicalPageSize + std::min( remainder, logicalPageSize );
|
||||
}
|
||||
}
|
||||
|
||||
265
src/3rdParty/libE57Format/src/Common.h
vendored
265
src/3rdParty/libE57Format/src/Common.h
vendored
@@ -1,183 +1,82 @@
|
||||
/*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Define the following symbol adds some functions to the API for implementation
|
||||
// purposes. These functions are not available to a normal API user.
|
||||
#define E57_INTERNAL_IMPLEMENTATION_ENABLE 1
|
||||
#include "E57Format.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Disable MSVC warning: warning C4224: nonstandard extension used : formal
|
||||
// parameter 'locale' was previously defined as a type
|
||||
#pragma warning( disable : 4224 )
|
||||
#endif
|
||||
|
||||
namespace e57
|
||||
{
|
||||
//!!! inline these rather than macros?
|
||||
#define E57_EXCEPTION1( ecode ) \
|
||||
( E57Exception( ( ecode ), ustring(), __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) ) )
|
||||
#define E57_EXCEPTION2( ecode, context ) \
|
||||
( E57Exception( ( ecode ), ( context ), __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) ) )
|
||||
|
||||
/// Create whitespace of given length, for indenting printouts in dump()
|
||||
/// functions
|
||||
inline std::string space( size_t n )
|
||||
{
|
||||
return ( std::string( n, ' ' ) );
|
||||
}
|
||||
|
||||
/// Convert number to decimal, hexadecimal, and binary strings (Note hex
|
||||
/// strings don't have leading zeros).
|
||||
template <class T> std::string toString( T x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << x;
|
||||
return ( ss.str() );
|
||||
}
|
||||
|
||||
inline std::string hexString( uint64_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "0x" << std::hex << std::setw( 16 ) << std::setfill( '0' ) << x;
|
||||
return ( ss.str() );
|
||||
}
|
||||
inline std::string hexString( uint32_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "0x" << std::hex << std::setw( 8 ) << std::setfill( '0' ) << x;
|
||||
return ( ss.str() );
|
||||
}
|
||||
inline std::string hexString( uint16_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "0x" << std::hex << std::setw( 4 ) << std::setfill( '0' ) << x;
|
||||
return ( ss.str() );
|
||||
}
|
||||
inline std::string hexString( uint8_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "0x" << std::hex << std::setw( 2 ) << std::setfill( '0' ) << static_cast<unsigned>( x );
|
||||
return ( ss.str() );
|
||||
}
|
||||
inline std::string binaryString( uint64_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for ( int i = 63; i >= 0; i-- )
|
||||
{
|
||||
ss << ( ( x & ( 1LL << i ) ) ? 1 : 0 );
|
||||
if ( i > 0 && i % 8 == 0 )
|
||||
ss << " ";
|
||||
}
|
||||
return ( ss.str() );
|
||||
}
|
||||
inline std::string binaryString( uint32_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for ( int i = 31; i >= 0; i-- )
|
||||
{
|
||||
ss << ( ( x & ( 1LL << i ) ) ? 1 : 0 );
|
||||
if ( i > 0 && i % 8 == 0 )
|
||||
ss << " ";
|
||||
}
|
||||
return ( ss.str() );
|
||||
}
|
||||
inline std::string binaryString( uint16_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for ( int i = 15; i >= 0; i-- )
|
||||
{
|
||||
ss << ( ( x & ( 1LL << i ) ) ? 1 : 0 );
|
||||
if ( i > 0 && i % 8 == 0 )
|
||||
ss << " ";
|
||||
}
|
||||
return ( ss.str() );
|
||||
}
|
||||
inline std::string binaryString( uint8_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for ( int i = 7; i >= 0; i-- )
|
||||
{
|
||||
ss << ( ( x & ( 1LL << i ) ) ? 1 : 0 );
|
||||
if ( i > 0 && i % 8 == 0 )
|
||||
ss << " ";
|
||||
}
|
||||
return ( ss.str() );
|
||||
}
|
||||
inline std::string hexString( int64_t x )
|
||||
{
|
||||
return ( hexString( static_cast<uint64_t>( x ) ) );
|
||||
}
|
||||
inline std::string hexString( int32_t x )
|
||||
{
|
||||
return ( hexString( static_cast<uint32_t>( x ) ) );
|
||||
}
|
||||
inline std::string hexString( int16_t x )
|
||||
{
|
||||
return ( hexString( static_cast<uint16_t>( x ) ) );
|
||||
}
|
||||
inline std::string hexString( int8_t x )
|
||||
{
|
||||
return ( hexString( static_cast<uint8_t>( x ) ) );
|
||||
}
|
||||
inline std::string binaryString( int64_t x )
|
||||
{
|
||||
return ( binaryString( static_cast<uint64_t>( x ) ) );
|
||||
}
|
||||
inline std::string binaryString( int32_t x )
|
||||
{
|
||||
return ( binaryString( static_cast<uint32_t>( x ) ) );
|
||||
}
|
||||
inline std::string binaryString( int16_t x )
|
||||
{
|
||||
return ( binaryString( static_cast<uint16_t>( x ) ) );
|
||||
}
|
||||
inline std::string binaryString( int8_t x )
|
||||
{
|
||||
return ( binaryString( static_cast<uint8_t>( x ) ) );
|
||||
}
|
||||
|
||||
using ImageFileImplSharedPtr = std::shared_ptr<class ImageFileImpl>;
|
||||
using ImageFileImplWeakPtr = std::weak_ptr<class ImageFileImpl>;
|
||||
using NodeImplSharedPtr = std::shared_ptr<class NodeImpl>;
|
||||
using NodeImplWeakPtr = std::weak_ptr<class NodeImpl>;
|
||||
|
||||
using StringList = std::vector<std::string>;
|
||||
using StringSet = std::set<std::string>;
|
||||
|
||||
//! generates a new random GUID
|
||||
std::string generateRandomGUID();
|
||||
}
|
||||
/*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Define the following symbol adds some functions to the API for implementation
|
||||
// purposes. These functions are not available to a normal API user.
|
||||
#define E57_INTERNAL_IMPLEMENTATION_ENABLE 1
|
||||
#include "E57Format.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Disable MSVC warning: warning C4224: nonstandard extension used : formal
|
||||
// parameter 'locale' was previously defined as a type
|
||||
#pragma warning( disable : 4224 )
|
||||
#endif
|
||||
|
||||
// Used to mark unused parameters to indicate intent and suppress warnings.
|
||||
#define E57_UNUSED( expr ) (void)( expr )
|
||||
|
||||
// For readability of preprocessor using E57_VALIDATION_LEVEL
|
||||
#define VALIDATION_OFF 0
|
||||
#define VALIDATION_BASIC 1
|
||||
#define VALIDATION_DEEP 2
|
||||
|
||||
#define VALIDATE_BASIC ( E57_VALIDATION_LEVEL > VALIDATION_OFF )
|
||||
#define VALIDATE_DEEP ( E57_VALIDATION_LEVEL > VALIDATION_BASIC )
|
||||
|
||||
// Determine if we are building 32 or 64 bit
|
||||
#if SIZE_MAX == UINT32_MAX
|
||||
#define E57_32_BIT
|
||||
#elif SIZE_MAX == UINT64_MAX
|
||||
#define E57_64_BIT
|
||||
#endif
|
||||
|
||||
namespace e57
|
||||
{
|
||||
#define E57_EXCEPTION1( ecode ) \
|
||||
( E57Exception( ( ecode ), ustring(), __FILE__, __LINE__, \
|
||||
static_cast<const char *>( __FUNCTION__ ) ) )
|
||||
#define E57_EXCEPTION2( ecode, context ) \
|
||||
( E57Exception( ( ecode ), ( context ), __FILE__, __LINE__, \
|
||||
static_cast<const char *>( __FUNCTION__ ) ) )
|
||||
|
||||
using ImageFileImplSharedPtr = std::shared_ptr<class ImageFileImpl>;
|
||||
using ImageFileImplWeakPtr = std::weak_ptr<class ImageFileImpl>;
|
||||
using NodeImplSharedPtr = std::shared_ptr<class NodeImpl>;
|
||||
using NodeImplWeakPtr = std::weak_ptr<class NodeImpl>;
|
||||
|
||||
using StringList = std::vector<std::string>;
|
||||
using StringSet = std::set<std::string>;
|
||||
|
||||
/// generates a new random GUID
|
||||
std::string generateRandomGUID();
|
||||
}
|
||||
|
||||
480
src/3rdParty/libE57Format/src/CompressedVectorNode.cpp
vendored
Normal file
480
src/3rdParty/libE57Format/src/CompressedVectorNode.cpp
vendored
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
* CompressedVectorNode.cpp - implementation of public functions of the
|
||||
* CompressedVectorNode class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file CompressedVectorNode.cpp
|
||||
|
||||
#include "CompressedVectorNodeImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether CompressedVectorNode class invariant is true
|
||||
@copydetails IntegerNode::checkInvariant()
|
||||
*/
|
||||
|
||||
void CompressedVectorNode::checkInvariant( bool doRecurse, bool doUpcast ) const
|
||||
{
|
||||
// If destImageFile not open, can't test invariant (almost every call would throw)
|
||||
if ( !destImageFile().isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If requested, call Node::checkInvariant
|
||||
if ( doUpcast )
|
||||
{
|
||||
static_cast<Node>( *this ).checkInvariant( false, false );
|
||||
}
|
||||
|
||||
// Check prototype is good Node
|
||||
prototype().checkInvariant( doRecurse );
|
||||
|
||||
// prototype attached state not same as this attached state
|
||||
if ( prototype().isAttached() != isAttached() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// prototype not root
|
||||
if ( !prototype().isRoot() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// prototype dest ImageFile not same as this dest ImageFile
|
||||
if ( prototype().destImageFile() != destImageFile() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Check codecs is good Node
|
||||
codecs().checkInvariant( doRecurse );
|
||||
|
||||
// codecs attached state not same as this attached state
|
||||
if ( codecs().isAttached() != isAttached() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// codecs not root
|
||||
if ( !codecs().isRoot() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// codecs dest ImageFile not same as this dest ImageFile
|
||||
if ( codecs().destImageFile() != destImageFile() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::CompressedVectorNode
|
||||
|
||||
@brief An E57 element containing ordered vector of child nodes, stored in an efficient binary
|
||||
format.
|
||||
|
||||
@details
|
||||
The CompressedVectorNode encodes very long sequences of identically typed records. In an E57 file,
|
||||
the per-point information (coordinates, intensity, color, time stamp etc.) are stored in a
|
||||
CompressedVectorNode. For time and space efficiency, the CompressedVectorNode data is stored in a
|
||||
binary section of the E57 file.
|
||||
|
||||
Conceptually, the CompressedVectorNode encodes a structure that looks very much like a homogeneous
|
||||
VectorNode object. However because of the huge volume of data (E57 files can store more than 10
|
||||
billion points) within a CompressedVectorNode, the functions for accessing the data are dramatically
|
||||
different. CompressedVectorNode data is accessed in large blocks of records (100s to 1000s at a
|
||||
time).
|
||||
|
||||
Two attributes are required to create a new CompressedVectorNode.
|
||||
|
||||
The first attribute describes the shape of the record that will be stored. This record type
|
||||
description is called the @c prototype of the CompressedVectorNode. Often the @c prototype will be a
|
||||
StructNode with a single level of named child elements. However, the prototype can be a tree of any
|
||||
depth consisting of the following node types: IntegerNode, ScaledIntegerNode, FloatNode, StringNode,
|
||||
StructureNode, or VectorNode (i.e. CompressedVectorNode and BlobNode are not allowed). Only the node
|
||||
types and attributes are used in the prototype, the values stored are ignored. For example, if the
|
||||
prototype contains an IntegerNode, with a value=0, minimum=0, maximum=1023, then this means that
|
||||
each record will contain an integer that can take any value in the interval [0,1023]. As a second
|
||||
example, if the prototype contains an ScaledIntegerNode, with a value=0, minimum=0, maximum=1023,
|
||||
scale=.001, offset=0 then this means that each record will contain an integer that can take any
|
||||
value in the interval [0,1023] and if a reader requests the scaledValue of the field, the rawValue
|
||||
should be multiplied by 0.001.
|
||||
|
||||
The second attribute needed to describe a new CompressedVectorNode is the @c codecs description of
|
||||
how the values of the records are to be represented on the disk. The codec object is a VectorNode of
|
||||
a particular format that describes the encoding for each field in the record, which codec will be
|
||||
used to transfer the values to and from the disk. Currently only one codec is defined for E57 files,
|
||||
the bitPackCodec, which copies the numbers from memory, removes any unused bit positions, and stores
|
||||
the without additional spaces on the disk. The bitPackCodec has no configuration options or
|
||||
parameters to tune. In the ASTM standard, if no codec is specified, the bitPackCodec is assumed. So
|
||||
specifying the @c codecs as an empty VectorNode is equivalent to requesting at all fields in the
|
||||
record be encoded with the bitPackCodec.
|
||||
|
||||
Other than the @c prototype and @c codecs attributes, the only other state directly accessible is
|
||||
the number of children (records) in the CompressedVectorNode. The read/write access to the contents
|
||||
of the CompressedVectorNode is coordinated by two other Foundation API objects:
|
||||
CompressedVectorReader and CompressedVectorWriter.
|
||||
|
||||
@section CompressedVectorNode_invariant Class Invariant
|
||||
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude CompressedVectorNode.cpp
|
||||
@skip void CompressedVectorNode::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see CompressedVectorReader, CompressedVectorWriter, Node
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Create an empty CompressedVectorNode, for writing, that will store records specified by the
|
||||
prototype.
|
||||
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
@param [in] prototype A tree that describes the fields in each record of the CompressedVectorNode.
|
||||
@param [in] codecs A VectorNode describing which codecs should be used for each field described in
|
||||
the prototype.
|
||||
|
||||
@details
|
||||
The @a destImageFile indicates which ImageFile the CompressedVectorNode will eventually be attached
|
||||
to. A node is attached to an ImageFile by adding it underneath the predefined root of the ImageFile
|
||||
(gotten from ImageFile::root). It is not an error to fail to attach the CompressedVectorNode to the
|
||||
@a destImageFile. It is an error to attempt to attach the CompressedVectorNode to a different
|
||||
ImageFile. The CompressedVectorNode may not be written to until it is attached to the destImageFile
|
||||
tree.
|
||||
|
||||
The @a prototype may be any tree consisting of only the following node types: IntegerNode,
|
||||
ScaledIntegerNode, FloatNode, StringNode, StructureNode, or VectorNode (i.e. CompressedVectorNode
|
||||
and BlobNode are not allowed). See CompressedVectorNode for discussion about the @a prototype
|
||||
argument.
|
||||
|
||||
The @a codecs must be a heterogeneous VectorNode with children as specified in the ASTM E57 data
|
||||
format standard. Since currently only one codec is supported (bitPackCodec), and it is the default,
|
||||
passing an empty VectorNode will specify that all record fields will be encoded with bitPackCodec.
|
||||
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
@pre @a prototype must be an unattached root node (i.e. !prototype.isAttached() &&
|
||||
prototype.isRoot())
|
||||
@pre @a prototype cannot contain BlobNodes or CompressedVectorNodes.
|
||||
@pre @a codecs must be an unattached root node (i.e. !codecs.isAttached() && codecs.isRoot())
|
||||
@post prototype.isAttached()
|
||||
@post codecs.isAttached()
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorBadPrototype
|
||||
@throw ::ErrorBadCodecs
|
||||
@throw ::ErrorAlreadyHasParent
|
||||
@throw ::ErrorDifferentDestImageFile
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see SourceDestBuffer, Node, CompressedVectorNode::reader, CompressedVectorNode::writer
|
||||
*/
|
||||
CompressedVectorNode::CompressedVectorNode( const ImageFile &destImageFile, const Node &prototype,
|
||||
const VectorNode &codecs ) :
|
||||
impl_( new CompressedVectorNodeImpl( destImageFile.impl() ) )
|
||||
{
|
||||
// Because of shared_ptr quirks, can't set prototype,codecs in CompressedVectorNodeImpl(), so set
|
||||
// it afterwards
|
||||
impl_->setPrototype( prototype.impl() );
|
||||
impl_->setCodecs( codecs.impl() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is this a root node.
|
||||
@copydetails Node::isRoot()
|
||||
*/
|
||||
bool CompressedVectorNode::isRoot() const
|
||||
{
|
||||
return impl_->isRoot();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return parent of node, or self if a root node.
|
||||
@copydetails Node::parent()
|
||||
*/
|
||||
Node CompressedVectorNode::parent() const
|
||||
{
|
||||
return Node( impl_->parent() );
|
||||
}
|
||||
|
||||
/// @brief Get absolute pathname of node.
|
||||
/// @copydetails Node::pathName()
|
||||
ustring CompressedVectorNode::pathName() const
|
||||
{
|
||||
return impl_->pathName();
|
||||
}
|
||||
|
||||
/// @brief Get elementName string, that identifies the node in its parent..
|
||||
/// @copydetails Node::elementName()
|
||||
ustring CompressedVectorNode::elementName() const
|
||||
{
|
||||
return impl_->elementName();
|
||||
}
|
||||
|
||||
/// @brief Get the ImageFile that was declared as the destination for the node when it was created.
|
||||
/// @copydetails Node::destImageFile()
|
||||
ImageFile CompressedVectorNode::destImageFile() const
|
||||
{
|
||||
return ImageFile( impl_->destImageFile() );
|
||||
}
|
||||
|
||||
/// @brief Has node been attached into the tree of an ImageFile.
|
||||
/// @copydetails Node::isAttached()
|
||||
bool CompressedVectorNode::isAttached() const
|
||||
{
|
||||
return impl_->isAttached();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get current number of records in a CompressedVectorNode.
|
||||
|
||||
@details
|
||||
For a CompressedVectorNode with an active CompressedVectorWriter, the returned number will reflect
|
||||
any writes completed.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return Current number of records in CompressedVectorNode.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::reader, CompressedVectorNode::writer
|
||||
*/
|
||||
int64_t CompressedVectorNode::childCount() const
|
||||
{
|
||||
return impl_->childCount();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the prototype tree that describes the types in the record.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return A smart Node handle referencing the root of the prototype tree.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::CompressedVectorNode, SourceDestBuffer, CompressedVectorNode::reader,
|
||||
CompressedVectorNode::writer
|
||||
*/
|
||||
Node CompressedVectorNode::prototype() const
|
||||
{
|
||||
return Node( impl_->getPrototype() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the codecs tree that describes the encoder/decoder configuration of the
|
||||
CompressedVectorNode.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return A smart VectorNode handle referencing the root of the codecs tree.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::CompressedVectorNode, SourceDestBuffer, CompressedVectorNode::reader,
|
||||
CompressedVectorNode::writer
|
||||
*/
|
||||
VectorNode CompressedVectorNode::codecs() const
|
||||
{
|
||||
return VectorNode( impl_->getCodecs() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void CompressedVectorNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void CompressedVectorNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Upcast a CompressedVectorNode handle to a generic Node handle.
|
||||
|
||||
@details
|
||||
An upcast is always safe, and the compiler can automatically insert it for initializations of Node
|
||||
variables and Node function arguments.
|
||||
|
||||
@return A smart Node handle referencing the underlying object.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see explanation in Node, Node::type(), CompressedVectorNode(const Node&)
|
||||
*/
|
||||
CompressedVectorNode::operator Node() const
|
||||
{
|
||||
// Implicitly upcast from shared_ptr<CompressedVectorNodeImpl> to SharedNodeImplPtr and
|
||||
// construct a Node object
|
||||
return Node( impl_ );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Downcast a generic Node handle to a CompressedVectorNode handle.
|
||||
|
||||
@param [in] n The generic handle to downcast.
|
||||
|
||||
@details
|
||||
The handle @a n must be for an underlying CompressedVectorNode, otherwise an exception is thrown. In
|
||||
designs that need to avoid the exception, use Node::type() to determine the actual type of the @a n
|
||||
before downcasting. This function must be explicitly called (c++ compiler cannot insert it
|
||||
automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
|
||||
@see Node::type(), CompressedVectorNode::operator, Node()
|
||||
*/
|
||||
CompressedVectorNode::CompressedVectorNode( const Node &n )
|
||||
{
|
||||
if ( n.type() != TypeCompressedVector )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadNodeDowncast, "nodeType=" + toString( n.type() ) );
|
||||
}
|
||||
|
||||
// Set our shared_ptr to the downcast shared_ptr
|
||||
impl_ = std::static_pointer_cast<CompressedVectorNodeImpl>( n.impl() );
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
CompressedVectorNode::CompressedVectorNode( std::shared_ptr<CompressedVectorNodeImpl> ni ) :
|
||||
impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
@brief Create an iterator object for writing a series of blocks of data to a CompressedVectorNode.
|
||||
|
||||
@param [in] sbufs Vector of memory buffers that will hold data to be written to a
|
||||
CompressedVectorNode.
|
||||
|
||||
@details
|
||||
See CompressedVectorWriter::write(std::vector<SourceDestBuffer>&, unsigned) for discussion about
|
||||
restrictions on @a sbufs.
|
||||
|
||||
The pathNames in the @a sbufs must match one-to-one with the terminal nodes (i.e. nodes that can
|
||||
have no children: IntegerNode, ScaledIntegerNode, FloatNode, StringNode) in this
|
||||
CompressedVectorNode's prototype. It is an error for two SourceDestBuffers in @a dbufs to identify
|
||||
the same terminal node in the prototype.
|
||||
|
||||
It is an error to call this function if the CompressedVectorNode already has any records (i.e. a
|
||||
CompressedVectorNode cannot be set twice).
|
||||
|
||||
@pre @a sbufs can't be empty (i.e. sbufs.length() > 0).
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable()).
|
||||
@pre The destination ImageFile can't have any readers or writers open
|
||||
(destImageFile().readerCount()==0 && destImageFile().writerCount()==0)
|
||||
@pre This CompressedVectorNode must be attached (i.e. isAttached()).
|
||||
@pre This CompressedVectorNode must have no records (i.e. childCount() == 0).
|
||||
|
||||
@return A smart CompressedVectorWriter handle referencing the underlying iterator object.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorSetTwice
|
||||
@throw ::ErrorTooManyWriters
|
||||
@throw ::ErrorTooManyReaders
|
||||
@throw ::ErrorNodeUnattached
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorBufferSizeMismatch
|
||||
@throw ::ErrorBufferDuplicatePathName
|
||||
@throw ::ErrorNoBufferForElement
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorWriter, SourceDestBuffer, CompressedVectorNode::CompressedVectorNode,
|
||||
CompressedVectorNode::prototype
|
||||
*/
|
||||
CompressedVectorWriter CompressedVectorNode::writer( std::vector<SourceDestBuffer> &sbufs )
|
||||
{
|
||||
return CompressedVectorWriter( impl_->writer( sbufs ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Create an iterator object for reading a series of blocks of data from a CompressedVectorNode.
|
||||
|
||||
@param [in] dbufs Vector of memory buffers that will receive data read from a CompressedVectorNode.
|
||||
|
||||
@details
|
||||
The pathNames in the @a dbufs must identify terminal nodes (i.e. node that can have no children:
|
||||
IntegerNode, ScaledIntegerNode, FloatNode, StringNode) in this CompressedVectorNode's prototype. It
|
||||
is an error for two SourceDestBuffers in @a dbufs to identify the same terminal node in the
|
||||
prototype. It is not an error to create a CompressedVectorReader for an empty CompressedVectorNode.
|
||||
|
||||
@pre @a dbufs can't be empty
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@pre The destination ImageFile can't have any writers open (destImageFile().writerCount()==0)
|
||||
@pre This CompressedVectorNode must be attached (i.e. isAttached()).
|
||||
|
||||
@return A smart CompressedVectorReader handle referencing the underlying iterator object.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorTooManyWriters
|
||||
@throw ::ErrorNodeUnattached
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorBufferSizeMismatch
|
||||
@throw ::ErrorBufferDuplicatePathName
|
||||
@throw ::ErrorBadCVHeader
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorReader, SourceDestBuffer, CompressedVectorNode::CompressedVectorNode,
|
||||
CompressedVectorNode::prototype
|
||||
*/
|
||||
CompressedVectorReader CompressedVectorNode::reader( const std::vector<SourceDestBuffer> &dbufs )
|
||||
{
|
||||
return CompressedVectorReader( impl_->reader( dbufs ) );
|
||||
}
|
||||
@@ -30,11 +30,13 @@
|
||||
#include "CompressedVectorReaderImpl.h"
|
||||
#include "CompressedVectorWriterImpl.h"
|
||||
#include "ImageFileImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
#include "VectorNodeImpl.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
CompressedVectorNodeImpl::CompressedVectorNodeImpl( ImageFileImplWeakPtr destImageFile ) : NodeImpl( destImageFile )
|
||||
CompressedVectorNodeImpl::CompressedVectorNodeImpl( ImageFileImplWeakPtr destImageFile ) :
|
||||
NodeImpl( destImageFile )
|
||||
{
|
||||
// don't checkImageFileOpen, NodeImpl() will do it
|
||||
}
|
||||
@@ -44,36 +46,37 @@ namespace e57
|
||||
// don't checkImageFileOpen, ctor did it
|
||||
|
||||
//??? check ok for proto, no Blob CompressedVector, empty?
|
||||
//??? throw E57_EXCEPTION2(E57_ERROR_BAD_PROTOTYPE)
|
||||
//??? throw E57_EXCEPTION2(ErrorBadPrototype)
|
||||
|
||||
/// Can't set prototype twice.
|
||||
// Can't set prototype twice.
|
||||
if ( prototype_ )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_SET_TWICE, "this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorSetTwice, "this->pathName=" + this->pathName() );
|
||||
}
|
||||
|
||||
/// prototype can't have a parent (must be a root node)
|
||||
// prototype can't have a parent (must be a root node)
|
||||
if ( !prototype->isRoot() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_ALREADY_HAS_PARENT,
|
||||
"this->pathName=" + this->pathName() + " prototype->pathName=" + prototype->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorAlreadyHasParent,
|
||||
"this->pathName=" + this->pathName() +
|
||||
" prototype->pathName=" + prototype->pathName() );
|
||||
}
|
||||
|
||||
/// Verify that prototype is destined for same ImageFile as this is
|
||||
// Verify that prototype is destined for same ImageFile as this is
|
||||
ImageFileImplSharedPtr thisDest( destImageFile() );
|
||||
ImageFileImplSharedPtr prototypeDest( prototype->destImageFile() );
|
||||
if ( thisDest != prototypeDest )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_DIFFERENT_DEST_IMAGEFILE, "this->destImageFile" + thisDest->fileName() +
|
||||
" prototype->destImageFile" +
|
||||
prototypeDest->fileName() );
|
||||
throw E57_EXCEPTION2( ErrorDifferentDestImageFile,
|
||||
"this->destImageFile" + thisDest->fileName() +
|
||||
" prototype->destImageFile" + prototypeDest->fileName() );
|
||||
}
|
||||
|
||||
//!!! check for incomplete CompressedVectors when closing file
|
||||
// !!! check for incomplete CompressedVectors when closing file
|
||||
prototype_ = prototype;
|
||||
|
||||
/// Note that prototype is not attached to CompressedVector in a parent/child
|
||||
/// relationship. This means that prototype is a root node (has no parent).
|
||||
// Note that prototype is not attached to CompressedVector in a parent/child
|
||||
// relationship. This means that prototype is a root node (has no parent).
|
||||
}
|
||||
|
||||
NodeImplSharedPtr CompressedVectorNodeImpl::getPrototype() const
|
||||
@@ -90,33 +93,34 @@ namespace e57
|
||||
// of strings, codec
|
||||
// substruct
|
||||
|
||||
/// Can't set codecs twice.
|
||||
// Can't set codecs twice.
|
||||
if ( codecs_ )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_SET_TWICE, "this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorSetTwice, "this->pathName=" + this->pathName() );
|
||||
}
|
||||
|
||||
/// codecs can't have a parent (must be a root node)
|
||||
// codecs can't have a parent (must be a root node)
|
||||
if ( !codecs->isRoot() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_ALREADY_HAS_PARENT,
|
||||
"this->pathName=" + this->pathName() + " codecs->pathName=" + codecs->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorAlreadyHasParent,
|
||||
"this->pathName=" + this->pathName() +
|
||||
" codecs->pathName=" + codecs->pathName() );
|
||||
}
|
||||
|
||||
/// Verify that codecs is destined for same ImageFile as this is
|
||||
// Verify that codecs is destined for same ImageFile as this is
|
||||
ImageFileImplSharedPtr thisDest( destImageFile() );
|
||||
ImageFileImplSharedPtr codecsDest( codecs->destImageFile() );
|
||||
if ( thisDest != codecsDest )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_DIFFERENT_DEST_IMAGEFILE, "this->destImageFile" + thisDest->fileName() +
|
||||
" codecs->destImageFile" +
|
||||
codecsDest->fileName() );
|
||||
throw E57_EXCEPTION2( ErrorDifferentDestImageFile,
|
||||
"this->destImageFile" + thisDest->fileName() +
|
||||
" codecs->destImageFile" + codecsDest->fileName() );
|
||||
}
|
||||
|
||||
codecs_ = codecs;
|
||||
|
||||
/// Note that codecs is not attached to CompressedVector in a parent/child
|
||||
/// relationship. This means that codecs is a root node (has no parent).
|
||||
// Note that codecs is not attached to CompressedVector in a parent/child
|
||||
// relationship. This means that codecs is a root node (has no parent).
|
||||
}
|
||||
|
||||
std::shared_ptr<VectorNodeImpl> CompressedVectorNodeImpl::getCodecs() const
|
||||
@@ -131,21 +135,22 @@ namespace e57
|
||||
|
||||
//??? is this test a good idea?
|
||||
|
||||
/// Same node type?
|
||||
if ( ni->type() != E57_COMPRESSED_VECTOR )
|
||||
// Same node type?
|
||||
if ( ni->type() != TypeCompressedVector )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
std::shared_ptr<CompressedVectorNodeImpl> cvi( std::static_pointer_cast<CompressedVectorNodeImpl>( ni ) );
|
||||
std::shared_ptr<CompressedVectorNodeImpl> cvi(
|
||||
std::static_pointer_cast<CompressedVectorNodeImpl>( ni ) );
|
||||
|
||||
/// recordCount must match
|
||||
// recordCount must match
|
||||
if ( recordCount_ != cvi->recordCount_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// Prototypes and codecs must match ???
|
||||
// Prototypes and codecs must match ???
|
||||
if ( !prototype_->isTypeEquivalent( cvi->prototype_ ) )
|
||||
{
|
||||
return ( false );
|
||||
@@ -160,21 +165,22 @@ namespace e57
|
||||
|
||||
bool CompressedVectorNodeImpl::isDefined( const ustring &pathName )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_NOT_IMPLEMENTED, "this->pathName=" + this->pathName() + " pathName=" + pathName );
|
||||
throw E57_EXCEPTION2( ErrorNotImplemented,
|
||||
"this->pathName=" + this->pathName() + " pathName=" + pathName );
|
||||
}
|
||||
|
||||
void CompressedVectorNodeImpl::setAttachedRecursive()
|
||||
{
|
||||
/// Mark this node as attached to an ImageFile
|
||||
// Mark this node as attached to an ImageFile
|
||||
isAttached_ = true;
|
||||
|
||||
/// Mark nodes in prototype tree, if defined
|
||||
// Mark nodes in prototype tree, if defined
|
||||
if ( prototype_ )
|
||||
{
|
||||
prototype_->setAttachedRecursive();
|
||||
}
|
||||
|
||||
/// Mark nodes in codecs tree if defined
|
||||
// Mark nodes in codecs tree if defined
|
||||
if ( codecs_ )
|
||||
{
|
||||
codecs_->setAttachedRecursive();
|
||||
@@ -187,13 +193,14 @@ namespace e57
|
||||
return ( recordCount_ );
|
||||
}
|
||||
|
||||
void CompressedVectorNodeImpl::checkLeavesInSet( const StringSet & /*pathNames*/, NodeImplSharedPtr /*origin*/ )
|
||||
void CompressedVectorNodeImpl::checkLeavesInSet( const StringSet & /*pathNames*/,
|
||||
NodeImplSharedPtr /*origin*/ )
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// Since only called for prototype nodes, shouldn't be able to get here since
|
||||
/// CompressedVectors can't be in prototypes
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "this->pathName=" + this->pathName() );
|
||||
// Since only called for prototype nodes, shouldn't be able to get here since
|
||||
// CompressedVectors can't be in prototypes
|
||||
throw E57_EXCEPTION2( ErrorInternal, "this->pathName=" + this->pathName() );
|
||||
}
|
||||
|
||||
void CompressedVectorNodeImpl::writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
|
||||
@@ -202,7 +209,7 @@ namespace e57
|
||||
// don't checkImageFileOpen
|
||||
|
||||
ustring fieldName;
|
||||
if ( forcedFieldName )
|
||||
if ( forcedFieldName != nullptr )
|
||||
{
|
||||
fieldName = forcedFieldName;
|
||||
}
|
||||
@@ -228,11 +235,11 @@ namespace e57
|
||||
cf << space( indent ) << "</" << fieldName << ">\n";
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void CompressedVectorNodeImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
os << space( indent ) << "type: CompressedVector"
|
||||
<< " (" << type() << ")" << std::endl;
|
||||
os << space( indent ) << "type: CompressedVector" << " (" << type() << ")"
|
||||
<< std::endl;
|
||||
NodeImpl::dump( indent, os );
|
||||
if ( prototype_ )
|
||||
{
|
||||
@@ -253,108 +260,115 @@ namespace e57
|
||||
os << space( indent ) << "codecs: <empty>" << std::endl;
|
||||
}
|
||||
os << space( indent ) << "recordCount: " << recordCount_ << std::endl;
|
||||
os << space( indent ) << "binarySectionLogicalStart: " << binarySectionLogicalStart_ << std::endl;
|
||||
os << space( indent ) << "binarySectionLogicalStart: " << binarySectionLogicalStart_
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::shared_ptr<CompressedVectorWriterImpl> CompressedVectorNodeImpl::writer( std::vector<SourceDestBuffer> sbufs )
|
||||
std::shared_ptr<CompressedVectorWriterImpl> CompressedVectorNodeImpl::writer(
|
||||
std::vector<SourceDestBuffer> sbufs )
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
ImageFileImplSharedPtr destImageFile( destImageFile_ );
|
||||
|
||||
/// Check don't have any writers/readers open for this ImageFile
|
||||
// Check don't have any writers/readers open for this ImageFile
|
||||
if ( destImageFile->writerCount() > 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_TOO_MANY_WRITERS,
|
||||
throw E57_EXCEPTION2( ErrorTooManyWriters,
|
||||
"fileName=" + destImageFile->fileName() +
|
||||
" writerCount=" + toString( destImageFile->writerCount() ) +
|
||||
" readerCount=" + toString( destImageFile->readerCount() ) );
|
||||
}
|
||||
if ( destImageFile->readerCount() > 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_TOO_MANY_READERS,
|
||||
throw E57_EXCEPTION2( ErrorTooManyReaders,
|
||||
"fileName=" + destImageFile->fileName() +
|
||||
" writerCount=" + toString( destImageFile->writerCount() ) +
|
||||
" readerCount=" + toString( destImageFile->readerCount() ) );
|
||||
}
|
||||
|
||||
/// sbufs can't be empty
|
||||
// sbufs can't be empty
|
||||
if ( sbufs.empty() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT, "fileName=" + destImageFile->fileName() );
|
||||
throw E57_EXCEPTION2( ErrorBadAPIArgument, "fileName=" + destImageFile->fileName() );
|
||||
}
|
||||
|
||||
if ( !destImageFile->isWriter() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_FILE_IS_READ_ONLY, "fileName=" + destImageFile->fileName() );
|
||||
throw E57_EXCEPTION2( ErrorFileReadOnly, "fileName=" + destImageFile->fileName() );
|
||||
}
|
||||
|
||||
if ( !isAttached() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_NODE_UNATTACHED, "fileName=" + destImageFile->fileName() );
|
||||
throw E57_EXCEPTION2( ErrorNodeUnattached, "fileName=" + destImageFile->fileName() );
|
||||
}
|
||||
|
||||
/// Get pointer to me (really shared_ptr<CompressedVectorNodeImpl>)
|
||||
// Get pointer to me (really shared_ptr<CompressedVectorNodeImpl>)
|
||||
NodeImplSharedPtr ni( shared_from_this() );
|
||||
|
||||
/// Downcast pointer to right type
|
||||
std::shared_ptr<CompressedVectorNodeImpl> cai( std::static_pointer_cast<CompressedVectorNodeImpl>( ni ) );
|
||||
// Downcast pointer to right type
|
||||
std::shared_ptr<CompressedVectorNodeImpl> cai(
|
||||
std::static_pointer_cast<CompressedVectorNodeImpl>( ni ) );
|
||||
|
||||
/// Return a shared_ptr to new object
|
||||
std::shared_ptr<CompressedVectorWriterImpl> cvwi( new CompressedVectorWriterImpl( cai, sbufs ) );
|
||||
// Return a shared_ptr to new object
|
||||
std::shared_ptr<CompressedVectorWriterImpl> cvwi(
|
||||
new CompressedVectorWriterImpl( cai, sbufs ) );
|
||||
return ( cvwi );
|
||||
}
|
||||
|
||||
std::shared_ptr<CompressedVectorReaderImpl> CompressedVectorNodeImpl::reader( std::vector<SourceDestBuffer> dbufs )
|
||||
std::shared_ptr<CompressedVectorReaderImpl> CompressedVectorNodeImpl::reader(
|
||||
std::vector<SourceDestBuffer> dbufs )
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
ImageFileImplSharedPtr destImageFile( destImageFile_ );
|
||||
|
||||
/// Check don't have any writers/readers open for this ImageFile
|
||||
// Check don't have any writers/readers open for this ImageFile
|
||||
if ( destImageFile->writerCount() > 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_TOO_MANY_WRITERS,
|
||||
throw E57_EXCEPTION2( ErrorTooManyWriters,
|
||||
"fileName=" + destImageFile->fileName() +
|
||||
" writerCount=" + toString( destImageFile->writerCount() ) +
|
||||
" readerCount=" + toString( destImageFile->readerCount() ) );
|
||||
}
|
||||
if ( destImageFile->readerCount() > 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_TOO_MANY_READERS,
|
||||
throw E57_EXCEPTION2( ErrorTooManyReaders,
|
||||
"fileName=" + destImageFile->fileName() +
|
||||
" writerCount=" + toString( destImageFile->writerCount() ) +
|
||||
" readerCount=" + toString( destImageFile->readerCount() ) );
|
||||
}
|
||||
|
||||
/// dbufs can't be empty
|
||||
// dbufs can't be empty
|
||||
if ( dbufs.empty() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT, "fileName=" + destImageFile->fileName() );
|
||||
throw E57_EXCEPTION2( ErrorBadAPIArgument, "fileName=" + destImageFile->fileName() );
|
||||
}
|
||||
|
||||
/// Can be read or write mode, but must be attached
|
||||
// Can be read or write mode, but must be attached
|
||||
if ( !isAttached() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_NODE_UNATTACHED, "fileName=" + destImageFile->fileName() );
|
||||
throw E57_EXCEPTION2( ErrorNodeUnattached, "fileName=" + destImageFile->fileName() );
|
||||
}
|
||||
|
||||
/// Get pointer to me (really shared_ptr<CompressedVectorNodeImpl>)
|
||||
// Get pointer to me (really shared_ptr<CompressedVectorNodeImpl>)
|
||||
NodeImplSharedPtr ni( shared_from_this() );
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
// cout << "constructing CAReader, ni:" << std::endl;
|
||||
// ni->dump(4);
|
||||
#endif
|
||||
|
||||
/// Downcast pointer to right type
|
||||
std::shared_ptr<CompressedVectorNodeImpl> cai( std::static_pointer_cast<CompressedVectorNodeImpl>( ni ) );
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
// Downcast pointer to right type
|
||||
std::shared_ptr<CompressedVectorNodeImpl> cai(
|
||||
std::static_pointer_cast<CompressedVectorNodeImpl>( ni ) );
|
||||
#ifdef E57_VERBOSE
|
||||
// cout<<"constructing CAReader, cai:"<<endl;
|
||||
// cai->dump(4);
|
||||
#endif
|
||||
/// Return a shared_ptr to new object
|
||||
std::shared_ptr<CompressedVectorReaderImpl> cvri( new CompressedVectorReaderImpl( cai, dbufs ) );
|
||||
// Return a shared_ptr to new object
|
||||
std::shared_ptr<CompressedVectorReaderImpl> cvri(
|
||||
new CompressedVectorReaderImpl( cai, dbufs ) );
|
||||
return ( cvri );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,13 +33,14 @@ namespace e57
|
||||
class CompressedVectorNodeImpl : public NodeImpl
|
||||
{
|
||||
public:
|
||||
CompressedVectorNodeImpl( ImageFileImplWeakPtr destImageFile );
|
||||
explicit CompressedVectorNodeImpl( ImageFileImplWeakPtr destImageFile );
|
||||
~CompressedVectorNodeImpl() override = default;
|
||||
|
||||
NodeType type() const override
|
||||
{
|
||||
return E57_COMPRESSED_VECTOR;
|
||||
return TypeCompressedVector;
|
||||
}
|
||||
|
||||
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
|
||||
bool isDefined( const ustring &pathName ) override;
|
||||
void setAttachedRecursive() override;
|
||||
@@ -64,20 +65,23 @@ namespace e57
|
||||
{
|
||||
return ( recordCount_ );
|
||||
}
|
||||
|
||||
uint64_t getBinarySectionLogicalStart() const
|
||||
{
|
||||
return ( binarySectionLogicalStart_ );
|
||||
}
|
||||
|
||||
void setRecordCount( int64_t recordCount )
|
||||
{
|
||||
recordCount_ = recordCount;
|
||||
}
|
||||
|
||||
void setBinarySectionLogicalStart( uint64_t binarySectionLogicalStart )
|
||||
{
|
||||
binarySectionLogicalStart_ = binarySectionLogicalStart;
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
|
||||
356
src/3rdParty/libE57Format/src/CompressedVectorReader.cpp
vendored
Normal file
356
src/3rdParty/libE57Format/src/CompressedVectorReader.cpp
vendored
Normal file
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* CompressedVectorReader.cpp - implementation of public functions of the
|
||||
* CompressedVectorReader class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file CompressedVectorReader.cpp
|
||||
|
||||
#include "CompressedVectorReaderImpl.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether CompressedVectorReader class invariant is true
|
||||
|
||||
@details
|
||||
This function checks at least the assertions in the documented class invariant description (see
|
||||
class reference page for this object). Other internal invariants that are implementation-dependent
|
||||
may also be checked. If any invariant clause is violated, an ::ErrorInvarianceViolation E57Exception
|
||||
is thrown.
|
||||
|
||||
@post No visible state is modified.
|
||||
*/
|
||||
void CompressedVectorReader::checkInvariant( bool /*doRecurse*/ )
|
||||
{
|
||||
// If this CompressedVectorReader is not open, can't test invariant (almost
|
||||
// every call would throw)
|
||||
if ( !isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CompressedVectorNode cv = compressedVectorNode();
|
||||
ImageFile imf = cv.destImageFile();
|
||||
|
||||
// If destImageFile not open, can't test invariant (almost every call would
|
||||
// throw)
|
||||
if ( !imf.isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Associated CompressedVectorNode must be attached to ImageFile
|
||||
if ( !cv.isAttached() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Dest ImageFile must have at least 1 reader (this one)
|
||||
if ( imf.readerCount() < 1 )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Dest ImageFile can't have any writers
|
||||
if ( imf.writerCount() != 0 )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::CompressedVectorReader
|
||||
|
||||
@brief An iterator object keeping track of a read in progress from a CompressedVectorNode.
|
||||
|
||||
@details
|
||||
A CompressedVectorReader object is a block iterator that reads blocks of records from a
|
||||
CompressedVectorNode and stores them in memory buffers (SourceDestBuffers). Blocks of records are
|
||||
processed rather than a single record-at-a-time for efficiency reasons. The CompressedVectorReader
|
||||
class encapsulates all the state that must be saved in between the processing of one record block
|
||||
and the next (e.g. partially read disk pages, or data decompression state). New memory buffers can
|
||||
be used for each record block read, or the previous buffers can be reused.
|
||||
|
||||
CompressedVectorReader objects have an open/closed state. Initially a newly created
|
||||
CompressedVectorReader is in the open state. After the API user calls CompressedVectorReader::close,
|
||||
the object will be in the closed state and no more data transfers will be possible.
|
||||
|
||||
There is no CompressedVectorReader constructor in the API. The function CompressedVectorNode::reader
|
||||
returns an already constructed CompressedVectorReader object with given memory buffers
|
||||
(SourceDestBuffers) already associated.
|
||||
|
||||
It is recommended to call CompressedVectorReader::close to gracefully end the transfer. Unlike the
|
||||
CompressedVectorWriter, not all fields in the record of the CompressedVectorNode are required to be
|
||||
read at one time.
|
||||
|
||||
@section CompressedVectorReader_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude CompressedVectorReader.cpp
|
||||
@skip void CompressedVectorReader::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see CompressedVectorNode, CompressedVectorWriter
|
||||
*/
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
CompressedVectorReader::CompressedVectorReader( std::shared_ptr<CompressedVectorReaderImpl> ni ) :
|
||||
impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
@brief Request transfer of blocks of data from CompressedVectorNode into
|
||||
previously designated destination buffers.
|
||||
|
||||
@details
|
||||
The SourceDestBuffers used are previously designated either in
|
||||
CompressedVectorNode::reader where this object was created, or in the last call
|
||||
to CompressedVectorReader::read(std::vector<SourceDestBuffer>&) where new
|
||||
buffers were designated. The function will always return the full number of
|
||||
records requested (the capacity of the SourceDestBuffers) unless it has reached
|
||||
the end of the CompressedVectorNode, in which case it will return less than the
|
||||
capacity of the SourceDestBuffers. Partial reads will store the records at the
|
||||
beginning of the SourceDestBuffers. It is not an error to call this function
|
||||
after all records in the CompressedVectorNode have been read (the function
|
||||
returns 0).
|
||||
|
||||
If a conversion or bounds error occurs during the transfer, the
|
||||
CompressedVectorReader is left in an undocumented state (it can't be used any
|
||||
further). If a file I/O or checksum error occurs during the transfer, both the
|
||||
CompressedVectorReader and the associated ImageFile are left in an undocumented
|
||||
state (they can't be used any further).
|
||||
|
||||
The API user is responsible for ensuring that the underlying memory buffers
|
||||
represented in the SourceDestBuffers still exist when this function is called.
|
||||
The E57 Foundation Implementation cannot detect that a memory buffer been
|
||||
destroyed.
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
@pre This CompressedVectorReader must be open (i.e isOpen())
|
||||
|
||||
@return The number of records read.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorReaderNotOpen
|
||||
@throw ::ErrorConversionRequired This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorValueNotRepresentable This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorScaledValueNotRepresentable This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorReal64TooLarge This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorExpectingNumeric This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorExpectingUString This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorBadCVPacket This CompressedVectorReader, associated
|
||||
ImageFile in undocumented state
|
||||
@throw ::ErrorSeekFailed This CompressedVectorReader, associated
|
||||
ImageFile in undocumented state
|
||||
@throw ::ErrorReadFailed This CompressedVectorReader, associated
|
||||
ImageFile in undocumented state
|
||||
@throw ::ErrorBadChecksum This CompressedVectorReader, associated
|
||||
ImageFile in undocumented state
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorReader::read(std::vector<SourceDestBuffer>&),
|
||||
CompressedVectorNode::reader, SourceDestBuffer,
|
||||
CompressedVectorReader::read(std::vector<SourceDestBuffer>&)
|
||||
*/
|
||||
unsigned CompressedVectorReader::read()
|
||||
{
|
||||
return impl_->read();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Request transfer of block of data from CompressedVectorNode into given destination buffers.
|
||||
|
||||
@param [in] dbufs Vector of memory buffers that will receive data read from a CompressedVectorNode.
|
||||
|
||||
@details
|
||||
The @a dbufs must all have the same capacity.
|
||||
|
||||
The specified @a dbufs must have same number of elements as previously designated SourceDestBuffer
|
||||
vector. The each SourceDestBuffer within @a dbufs must be identical to the previously designated
|
||||
SourceDestBuffer except for capacity and buffer address.
|
||||
|
||||
The @a dbufs locations are saved so that a later call to CompressedVectorReader::read() can be used
|
||||
without having to re-specify the SourceDestBuffers.
|
||||
|
||||
The function will always return the full number of records requested (the capacity of the
|
||||
SourceDestBuffers) unless it has reached the end of the CompressedVectorNode, in which case it will
|
||||
return less than the capacity of the SourceDestBuffers. Partial reads will store the records at the
|
||||
beginning of the SourceDestBuffers. It is not an error to call this function after all records in
|
||||
the CompressedVectorNode have been read (the function returns 0).
|
||||
|
||||
If a conversion or bounds error occurs during the transfer, the CompressedVectorReader is left in an
|
||||
undocumented state (it can't be used any further). If a file I/O or checksum error occurs during the
|
||||
transfer, both the CompressedVectorReader and the associated ImageFile are left in an undocumented
|
||||
state (they can't be used any further).
|
||||
|
||||
The API user is responsible for ensuring that the underlying memory buffers represented in the
|
||||
SourceDestBuffers still exist when this function is called. The E57 Foundation Implementation cannot
|
||||
detect that a memory buffer been destroyed.
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
@pre This CompressedVectorReader must be open (i.e isOpen())
|
||||
|
||||
@return The number of records read.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorReaderNotOpen
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorBufferSizeMismatch
|
||||
@throw ::ErrorBufferDuplicatePathName
|
||||
@throw ::ErrorConversionRequired This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorValueNotRepresentable This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorScaledValueNotRepresentable This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorReal64TooLarge This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorExpectingNumeric This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorExpectingUString This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorBadCVPacket This CompressedVectorReader, associated ImageFile in undocumented state
|
||||
@throw ::ErrorSeekFailed This CompressedVectorReader, associated ImageFile in undocumented state
|
||||
@throw ::ErrorReadFailed This CompressedVectorReader, associated ImageFile in undocumented state
|
||||
@throw ::ErrorBadChecksum This CompressedVectorReader, associated ImageFile in undocumented state
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorReader::read(), CompressedVectorNode::reader, SourceDestBuffer
|
||||
*/
|
||||
unsigned CompressedVectorReader::read( std::vector<SourceDestBuffer> &dbufs )
|
||||
{
|
||||
return impl_->read( dbufs );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Set record number of CompressedVectorNode where next read will start.
|
||||
|
||||
@param [in] recordNumber The index of record in CompressedVectorNode where next read using this
|
||||
CompressedVectorReader will start.
|
||||
|
||||
@details
|
||||
This function may be called at any time (as long as ImageFile and CompressedVectorReader are open).
|
||||
The next read will start at the given recordNumber. It is not an error to seek to recordNumber =
|
||||
childCount() (i.e. to one record past end of CompressedVectorNode).
|
||||
|
||||
@pre @a recordNumber <= childCount() of CompressedVectorNode.
|
||||
@pre The associated ImageFile must be open.
|
||||
@pre This CompressedVectorReader must be open (i.e isOpen())
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorReaderNotOpen
|
||||
@throw ::ErrorBadCVPacket
|
||||
@throw ::ErrorSeekFailed
|
||||
@throw ::ErrorReadFailed
|
||||
@throw ::ErrorBadChecksum
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::reader
|
||||
*/
|
||||
void CompressedVectorReader::seek( int64_t recordNumber )
|
||||
{
|
||||
impl_->seek( recordNumber );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief End the read operation.
|
||||
|
||||
@details
|
||||
It is recommended that this function be called to gracefully end a transfer to a
|
||||
CompressedVectorNode. It is not an error to call this function if the CompressedVectorReader is
|
||||
already closed. This function will cause the CompressedVectorReader to enter the closed state, and
|
||||
any further transfers requests will fail.
|
||||
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorReader::isOpen, CompressedVectorNode::reader
|
||||
*/
|
||||
void CompressedVectorReader::close()
|
||||
{
|
||||
impl_->close();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Test whether CompressedVectorReader is still open for reading.
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorReader::close, CompressedVectorNode::reader
|
||||
*/
|
||||
bool CompressedVectorReader::isOpen()
|
||||
{
|
||||
return impl_->isOpen();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return the CompressedVectorNode being read.
|
||||
|
||||
@details
|
||||
It is not an error if this CompressedVectorReader is closed.
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
|
||||
@return A smart CompressedVectorNode handle referencing the underlying object being read from.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorReader::close, CompressedVectorNode::reader
|
||||
*/
|
||||
CompressedVectorNode CompressedVectorReader::compressedVectorNode() const
|
||||
{
|
||||
return impl_->compressedVectorNode();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void CompressedVectorReader::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void CompressedVectorReader::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
@@ -32,55 +32,58 @@
|
||||
#include "Packet.h"
|
||||
#include "SectionHeaders.h"
|
||||
#include "SourceDestBufferImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
CompressedVectorReaderImpl::CompressedVectorReaderImpl( std::shared_ptr<CompressedVectorNodeImpl> cvi,
|
||||
std::vector<SourceDestBuffer> &dbufs ) :
|
||||
CompressedVectorReaderImpl::CompressedVectorReaderImpl(
|
||||
std::shared_ptr<CompressedVectorNodeImpl> cvi,
|
||||
std::vector<SourceDestBuffer> &dbufs ) :
|
||||
isOpen_( false ), // set to true when succeed below
|
||||
cVector_( cvi )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "CompressedVectorReaderImpl() called" << std::endl; //???
|
||||
#endif
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
/// Allow reading of a completed CompressedVector, whether file is being read
|
||||
/// or currently being written.
|
||||
///??? what other situations need checking for?
|
||||
///??? check if CV not yet written to?
|
||||
///??? file in error state?
|
||||
// Allow reading of a completed CompressedVector, whether file is being read
|
||||
// or currently being written.
|
||||
//??? what other situations need checking for?
|
||||
//??? check if CV not yet written to?
|
||||
//??? file in error state?
|
||||
|
||||
/// Empty dbufs is an error
|
||||
// Empty dbufs is an error
|
||||
if ( dbufs.empty() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT,
|
||||
"imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorBadAPIArgument, "imageFileName=" + cVector_->imageFileName() +
|
||||
" cvPathName=" + cVector_->pathName() );
|
||||
}
|
||||
|
||||
/// Get CompressedArray's prototype node (all array elements must match this
|
||||
/// type)
|
||||
// Get CompressedArray's prototype node (all array elements must match this
|
||||
// type)
|
||||
proto_ = cVector_->getPrototype();
|
||||
|
||||
/// Check dbufs well formed (matches proto exactly)
|
||||
// Check dbufs well formed (matches proto exactly)
|
||||
setBuffers( dbufs );
|
||||
|
||||
/// For each dbuf, create an appropriate Decoder based on the cVector_
|
||||
/// attributes
|
||||
// For each dbuf, create an appropriate Decoder based on the cVector_
|
||||
// attributes
|
||||
for ( unsigned i = 0; i < dbufs_.size(); i++ )
|
||||
{
|
||||
std::vector<SourceDestBuffer> theDbuf;
|
||||
theDbuf.push_back( dbufs.at( i ) );
|
||||
|
||||
std::shared_ptr<Decoder> decoder = Decoder::DecoderFactory( i, cVector_.get(), theDbuf, ustring() );
|
||||
std::shared_ptr<Decoder> decoder =
|
||||
Decoder::DecoderFactory( i, cVector_.get(), theDbuf, ustring() );
|
||||
|
||||
/// Calc which stream the given path belongs to. This depends on position
|
||||
/// of the node in the proto tree.
|
||||
// Calc which stream the given path belongs to. This depends on position
|
||||
// of the node in the proto tree.
|
||||
NodeImplSharedPtr readNode = proto_->get( dbufs.at( i ).pathName() );
|
||||
uint64_t bytestreamNumber = 0;
|
||||
if ( !proto_->findTerminalPosition( readNode, bytestreamNumber ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "dbufIndex=" + toString( i ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "dbufIndex=" + toString( i ) );
|
||||
}
|
||||
|
||||
channels_.emplace_back( dbufs.at( i ), decoder, static_cast<unsigned>( bytestreamNumber ),
|
||||
@@ -89,72 +92,88 @@ namespace e57
|
||||
|
||||
recordCount_ = 0;
|
||||
|
||||
/// Get how many records are actually defined
|
||||
// Get how many records are actually defined
|
||||
maxRecordCount_ = cvi->childCount();
|
||||
|
||||
ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
|
||||
|
||||
//??? what if fault in this constructor?
|
||||
cache_ = new PacketReadCache( imf->file_, 32 );
|
||||
|
||||
/// Read CompressedVector section header
|
||||
CompressedVectorSectionHeader sectionHeader;
|
||||
// Check the file offset of this vector - it must be positive
|
||||
uint64_t sectionLogicalStart = cVector_->getBinarySectionLogicalStart();
|
||||
if ( sectionLogicalStart == 0 )
|
||||
{
|
||||
//??? should have caught this before got here, in XML read, get this if CV
|
||||
// wasn't written to
|
||||
// by writer.
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL,
|
||||
"imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName() );
|
||||
// Older versions of this library (and E57RefImpl) incorrectly set the "fileOffset" to 0
|
||||
// when "recordCount" is 0. "fileOffset" must be greater than 0 (Table 9 in the standard).
|
||||
if ( maxRecordCount_ == 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorData3DReadInvalidZeroRecords,
|
||||
"fileOffset cannot be 0; cvPathName=" + cVector_->pathName() +
|
||||
" imageFileName=" + cVector_->imageFileName() );
|
||||
}
|
||||
|
||||
//??? should have caught this before got here, in XML read, get this if CV wasn't written
|
||||
// to by writer.
|
||||
throw E57_EXCEPTION2( ErrorInternal, "imageFileName=" + cVector_->imageFileName() +
|
||||
" cvPathName=" + cVector_->pathName() );
|
||||
}
|
||||
|
||||
// Read CompressedVector section header
|
||||
CompressedVectorSectionHeader sectionHeader;
|
||||
imf->file_->seek( sectionLogicalStart, CheckedFile::Logical );
|
||||
imf->file_->read( reinterpret_cast<char *>( §ionHeader ), sizeof( sectionHeader ) );
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#if VALIDATE_BASIC
|
||||
sectionHeader.verify( imf->file_->length( CheckedFile::Physical ) );
|
||||
#endif
|
||||
|
||||
/// Pre-calc end of section, so can tell when we are out of packets.
|
||||
// Pre-calc end of section, so can tell when we are out of packets.
|
||||
sectionEndLogicalOffset_ = sectionLogicalStart + sectionHeader.sectionLogicalLength;
|
||||
|
||||
/// Convert physical offset to first data packet to logical
|
||||
uint64_t dataLogicalOffset = imf->file_->physicalToLogical( sectionHeader.dataPhysicalOffset );
|
||||
// Convert physical offset to first data packet to logical
|
||||
uint64_t dataLogicalOffset =
|
||||
imf->file_->physicalToLogical( sectionHeader.dataPhysicalOffset );
|
||||
|
||||
/// Verify that packet given by dataPhysicalOffset is actually a data packet,
|
||||
/// init channels
|
||||
//??? what if fault in this constructor?
|
||||
cache_ = new PacketReadCache( imf->file_, 32 );
|
||||
|
||||
// Verify that packet given by dataPhysicalOffset is actually a data packet,
|
||||
// init channels
|
||||
{
|
||||
char *anyPacket = nullptr;
|
||||
std::unique_ptr<PacketLock> packetLock = cache_->lock( dataLogicalOffset, anyPacket );
|
||||
|
||||
auto dpkt = reinterpret_cast<DataPacket *>( anyPacket );
|
||||
|
||||
/// Double check that have a data packet
|
||||
// Double check that have a data packet
|
||||
if ( dpkt->header.packetType != DATA_PACKET )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( dpkt->header.packetType ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket,
|
||||
"packetType=" + toString( dpkt->header.packetType ) );
|
||||
}
|
||||
|
||||
/// Have good packet, initialize channels
|
||||
for ( auto &channel : channels_ )
|
||||
// Have good packet, initialize channels if we have records
|
||||
if ( maxRecordCount_ > 0 )
|
||||
{
|
||||
channel.currentPacketLogicalOffset = dataLogicalOffset;
|
||||
channel.currentBytestreamBufferIndex = 0;
|
||||
channel.currentBytestreamBufferLength = dpkt->getBytestreamBufferLength( channel.bytestreamNumber );
|
||||
for ( auto &channel : channels_ )
|
||||
{
|
||||
channel.currentPacketLogicalOffset = dataLogicalOffset;
|
||||
channel.currentBytestreamBufferIndex = 0;
|
||||
channel.currentBytestreamBufferLength =
|
||||
dpkt->getBytestreamBufferLength( channel.bytestreamNumber );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Just before return (and can't throw) increment reader count ??? safer
|
||||
/// way to assure don't miss close?
|
||||
// Just before return (and can't throw) increment reader count ??? safer
|
||||
// way to assure don't miss close?
|
||||
imf->incrReaderCount();
|
||||
|
||||
/// If get here, the reader is open
|
||||
// If get here, the reader is open
|
||||
isOpen_ = true;
|
||||
}
|
||||
|
||||
CompressedVectorReaderImpl::~CompressedVectorReaderImpl()
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "~CompressedVectorReaderImpl() called" << std::endl; //???
|
||||
// dump(4);
|
||||
#endif
|
||||
@@ -163,7 +182,7 @@ namespace e57
|
||||
{
|
||||
try
|
||||
{
|
||||
close(); ///??? what if already closed?
|
||||
close(); //??? what if already closed?
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
@@ -174,27 +193,28 @@ namespace e57
|
||||
|
||||
void CompressedVectorReaderImpl::setBuffers( std::vector<SourceDestBuffer> &dbufs )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
/// don't checkReaderOpen
|
||||
// don't checkImageFileOpen
|
||||
// don't checkReaderOpen
|
||||
|
||||
/// Check dbufs well formed: no dups, no extra, missing is ok
|
||||
// Check dbufs well formed: no dups, no extra, missing is ok
|
||||
proto_->checkBuffers( dbufs, true );
|
||||
|
||||
/// If had previous dbufs_, check to see if new ones have changed in
|
||||
/// incompatible way
|
||||
// If had previous dbufs_, check to see if new ones have changed in
|
||||
// incompatible way
|
||||
if ( !dbufs_.empty() )
|
||||
{
|
||||
if ( dbufs_.size() != dbufs.size() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BUFFERS_NOT_COMPATIBLE,
|
||||
"oldSize=" + toString( dbufs_.size() ) + " newSize=" + toString( dbufs.size() ) );
|
||||
throw E57_EXCEPTION2( ErrorBuffersNotCompatible,
|
||||
"oldSize=" + toString( dbufs_.size() ) +
|
||||
" newSize=" + toString( dbufs.size() ) );
|
||||
}
|
||||
for ( size_t i = 0; i < dbufs_.size(); i++ )
|
||||
{
|
||||
std::shared_ptr<SourceDestBufferImpl> oldBuf = dbufs_[i].impl();
|
||||
std::shared_ptr<SourceDestBufferImpl> newBuf = dbufs[i].impl();
|
||||
|
||||
/// Throw exception if old and new not compatible
|
||||
// Throw exception if old and new not compatible
|
||||
oldBuf->checkCompatible( newBuf );
|
||||
}
|
||||
}
|
||||
@@ -204,12 +224,12 @@ namespace e57
|
||||
|
||||
unsigned CompressedVectorReaderImpl::read( std::vector<SourceDestBuffer> &dbufs )
|
||||
{
|
||||
/// don't checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__), read() will
|
||||
/// do it
|
||||
// don't checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__), read() will
|
||||
// do it
|
||||
|
||||
checkReaderOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
/// Check compatible with current dbufs
|
||||
// Check compatible with current dbufs
|
||||
setBuffers( dbufs );
|
||||
|
||||
return ( read() );
|
||||
@@ -217,46 +237,46 @@ namespace e57
|
||||
|
||||
unsigned CompressedVectorReaderImpl::read()
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "CompressedVectorReaderImpl::read() called" << std::endl; //???
|
||||
#endif
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
checkReaderOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
/// Rewind all dbufs so start writing to them at beginning
|
||||
// Rewind all dbufs so start writing to them at beginning
|
||||
for ( auto &dbuf : dbufs_ )
|
||||
{
|
||||
dbuf.impl()->rewind();
|
||||
}
|
||||
|
||||
/// Allow decoders to use data they already have in their queue to fill newly
|
||||
/// empty dbufs This helps to keep decoder input queues smaller, which
|
||||
/// reduces backtracking in the packet cache.
|
||||
// Allow decoders to use data they already have in their queue to fill newly
|
||||
// empty dbufs This helps to keep decoder input queues smaller, which
|
||||
// reduces backtracking in the packet cache.
|
||||
for ( auto &channel : channels_ )
|
||||
{
|
||||
channel.decoder->inputProcess( nullptr, 0 );
|
||||
}
|
||||
|
||||
/// Loop until every dbuf is full or we have reached end of the binary
|
||||
/// section.
|
||||
// Loop until every dbuf is full or we have reached end of the binary
|
||||
// section.
|
||||
while ( true )
|
||||
{
|
||||
/// Find the earliest packet position for channels that are still hungry
|
||||
/// It's important to call inputProcess of the decoders before this call,
|
||||
/// so current hungriness level is reflected.
|
||||
// Find the earliest packet position for channels that are still hungry
|
||||
// It's important to call inputProcess of the decoders before this call,
|
||||
// so current hungriness level is reflected.
|
||||
uint64_t earliestPacketLogicalOffset = earliestPacketNeededForInput();
|
||||
|
||||
/// If nobody's hungry, we are done with the read
|
||||
if ( earliestPacketLogicalOffset == E57_UINT64_MAX )
|
||||
// If nobody's hungry, we are done with the read
|
||||
if ( earliestPacketLogicalOffset == UINT64_MAX )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/// Feed packet to the hungry decoders
|
||||
// Feed packet to the hungry decoders
|
||||
feedPacketToDecoders( earliestPacketLogicalOffset );
|
||||
}
|
||||
|
||||
/// Verify that each channel produced the same number of records
|
||||
// Verify that each channel produced the same number of records
|
||||
unsigned outputCount = 0;
|
||||
for ( unsigned i = 0; i < channels_.size(); i++ )
|
||||
{
|
||||
@@ -269,20 +289,21 @@ namespace e57
|
||||
{
|
||||
if ( outputCount != chan->dbuf.impl()->nextIndex() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "outputCount=" + toString( outputCount ) + " nextIndex=" +
|
||||
toString( chan->dbuf.impl()->nextIndex() ) );
|
||||
throw E57_EXCEPTION2(
|
||||
ErrorInternal, "outputCount=" + toString( outputCount ) +
|
||||
" nextIndex=" + toString( chan->dbuf.impl()->nextIndex() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return number of records transferred to each dbuf.
|
||||
// Return number of records transferred to each dbuf.
|
||||
return outputCount;
|
||||
}
|
||||
|
||||
uint64_t CompressedVectorReaderImpl::earliestPacketNeededForInput() const
|
||||
{
|
||||
uint64_t earliestPacketLogicalOffset = E57_UINT64_MAX;
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
uint64_t earliestPacketLogicalOffset = UINT64_MAX;
|
||||
#ifdef E57_VERBOSE
|
||||
unsigned earliestChannel = 0;
|
||||
#endif
|
||||
|
||||
@@ -290,29 +311,29 @@ namespace e57
|
||||
{
|
||||
const DecodeChannel *chan = &channels_[i];
|
||||
|
||||
/// Test if channel needs more input.
|
||||
/// Important to call inputProcess just before this, so these tests work.
|
||||
// Test if channel needs more input.
|
||||
// Important to call inputProcess just before this, so these tests work.
|
||||
if ( !chan->isOutputBlocked() && !chan->inputFinished )
|
||||
{
|
||||
/// Check if earliest so far
|
||||
// Check if earliest so far
|
||||
if ( chan->currentPacketLogicalOffset < earliestPacketLogicalOffset )
|
||||
{
|
||||
earliestPacketLogicalOffset = chan->currentPacketLogicalOffset;
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
earliestChannel = i;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
if ( earliestPacketLogicalOffset == E57_UINT64_MAX )
|
||||
#ifdef E57_VERBOSE
|
||||
if ( earliestPacketLogicalOffset == UINT64_MAX )
|
||||
{
|
||||
std::cout << "earliestPacketNeededForInput returning none found" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "earliestPacketNeededForInput returning " << earliestPacketLogicalOffset << " for channel["
|
||||
<< earliestChannel << "]" << std::endl;
|
||||
std::cout << "earliestPacketNeededForInput returning " << earliestPacketLogicalOffset
|
||||
<< " for channel[" << earliestChannel << "]" << std::endl;
|
||||
}
|
||||
#endif
|
||||
return earliestPacketLogicalOffset;
|
||||
@@ -327,9 +348,11 @@ namespace e57
|
||||
return reinterpret_cast<DataPacket *>( packet );
|
||||
}
|
||||
|
||||
inline bool _alreadyReadPacket( const DecodeChannel &channel, uint64_t currentPacketLogicalOffset )
|
||||
inline bool _alreadyReadPacket( const DecodeChannel &channel,
|
||||
uint64_t currentPacketLogicalOffset )
|
||||
{
|
||||
return ( ( channel.currentPacketLogicalOffset != currentPacketLogicalOffset ) || channel.isOutputBlocked() );
|
||||
return ( ( channel.currentPacketLogicalOffset != currentPacketLogicalOffset ) ||
|
||||
channel.isOutputBlocked() );
|
||||
}
|
||||
|
||||
void CompressedVectorReaderImpl::feedPacketToDecoders( uint64_t currentPacketLogicalOffset )
|
||||
@@ -337,21 +360,18 @@ namespace e57
|
||||
// Get packet at currentPacketLogicalOffset into memory.
|
||||
auto dpkt = dataPacket( currentPacketLogicalOffset );
|
||||
|
||||
// Double check that have a data packet. Should have already determined
|
||||
// this.
|
||||
// Double check that have a data packet. Should have already determined this.
|
||||
if ( dpkt->header.packetType != DATA_PACKET )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetType=" + toString( dpkt->header.packetType ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "packetType=" + toString( dpkt->header.packetType ) );
|
||||
}
|
||||
|
||||
// Read earliest packet into cache and send data to decoders with unblocked
|
||||
// output
|
||||
// Read earliest packet into cache and send data to decoders with unblocked output
|
||||
|
||||
bool anyChannelHasExhaustedPacket = false;
|
||||
uint64_t nextPacketLogicalOffset = E57_UINT64_MAX;
|
||||
uint64_t nextPacketLogicalOffset = UINT64_MAX;
|
||||
|
||||
// Feed bytestreams to channels with unblocked output that are reading from
|
||||
// this packet
|
||||
// Feed bytestreams to channels with unblocked output that are reading from this packet
|
||||
for ( DecodeChannel &channel : channels_ )
|
||||
{
|
||||
// Skip channels that have already read this packet.
|
||||
@@ -367,9 +387,10 @@ namespace e57
|
||||
// Double check we are not off end of buffer
|
||||
if ( channel.currentBytestreamBufferIndex > bsbLength )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL,
|
||||
"currentBytestreamBufferIndex =" + toString( channel.currentBytestreamBufferIndex ) +
|
||||
" bsbLength=" + toString( bsbLength ) );
|
||||
throw E57_EXCEPTION2(
|
||||
ErrorInternal,
|
||||
"currentBytestreamBufferIndex =" + toString( channel.currentBytestreamBufferIndex ) +
|
||||
" bsbLength=" + toString( bsbLength ) );
|
||||
}
|
||||
|
||||
// Calc where we are in the buffer
|
||||
@@ -378,23 +399,24 @@ namespace e57
|
||||
|
||||
if ( &uneatenStart[uneatenLength] > &bsbStart[bsbLength] )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "uneatenLength=" + toString( uneatenLength ) +
|
||||
" bsbLength=" + toString( bsbLength ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "uneatenLength=" + toString( uneatenLength ) +
|
||||
" bsbLength=" + toString( bsbLength ) );
|
||||
}
|
||||
|
||||
// Feed into decoder
|
||||
const size_t bytesProcessed = channel.decoder->inputProcess( uneatenStart, uneatenLength );
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " stream[" << channel.bytestreamNumber << "]: feeding decoder " << uneatenLength << " bytes"
|
||||
<< std::endl;
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " stream[" << channel.bytestreamNumber << "]: feeding decoder "
|
||||
<< uneatenLength << " bytes" << std::endl;
|
||||
|
||||
if ( uneatenLength == 0 )
|
||||
{
|
||||
channel.dump( 8 );
|
||||
}
|
||||
|
||||
std::cout << " stream[" << channel.bytestreamNumber << "]: bytesProcessed=" << bytesProcessed << std::endl;
|
||||
std::cout << " stream[" << channel.bytestreamNumber
|
||||
<< "]: bytesProcessed=" << bytesProcessed << std::endl;
|
||||
#endif
|
||||
|
||||
// Adjust counts of bytestream location
|
||||
@@ -404,12 +426,13 @@ namespace e57
|
||||
// packet
|
||||
if ( channel.isInputBlocked() )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " stream[" << channel.bytestreamNumber << "] has exhausted its input in current packet"
|
||||
<< std::endl;
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " stream[" << channel.bytestreamNumber
|
||||
<< "] has exhausted its input in current packet" << std::endl;
|
||||
#endif
|
||||
anyChannelHasExhaustedPacket = true;
|
||||
nextPacketLogicalOffset = currentPacketLogicalOffset + dpkt->header.packetLogicalLengthMinus1 + 1;
|
||||
nextPacketLogicalOffset =
|
||||
currentPacketLogicalOffset + dpkt->header.packetLogicalLengthMinus1 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,7 +448,7 @@ namespace e57
|
||||
// Some channel has exhausted this packet, so find next data packet and
|
||||
// update currentPacketLogicalOffset for all interested channels.
|
||||
|
||||
if ( nextPacketLogicalOffset < E57_UINT64_MAX )
|
||||
if ( nextPacketLogicalOffset < UINT64_MAX )
|
||||
{ //??? huh?
|
||||
// Get packet at nextPacketLogicalOffset into memory.
|
||||
dpkt = dataPacket( nextPacketLogicalOffset );
|
||||
@@ -444,9 +467,10 @@ namespace e57
|
||||
|
||||
// It is OK if the next packet doesn't contain any data for this
|
||||
// channel, will skip packet on next iter of loop
|
||||
channel.currentBytestreamBufferLength = dpkt->getBytestreamBufferLength( channel.bytestreamNumber );
|
||||
channel.currentBytestreamBufferLength =
|
||||
dpkt->getBytestreamBufferLength( channel.bytestreamNumber );
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " set new stream buffer for channel[" << channel.bytestreamNumber
|
||||
<< "], length=" << channel.currentBytestreamBufferLength << std::endl;
|
||||
#endif
|
||||
@@ -457,7 +481,7 @@ namespace e57
|
||||
{
|
||||
// Reached end without finding data packet, mark exhausted channels as
|
||||
// finished
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " at end of data packets" << std::endl;
|
||||
#endif
|
||||
if ( nextPacketLogicalOffset >= sectionEndLogicalOffset_ )
|
||||
@@ -470,8 +494,9 @@ namespace e57
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " Marking channel[" << channel.bytestreamNumber << "] as finished" << std::endl;
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " Marking channel[" << channel.bytestreamNumber << "] as finished"
|
||||
<< std::endl;
|
||||
#endif
|
||||
channel.inputFinished = true;
|
||||
}
|
||||
@@ -481,74 +506,78 @@ namespace e57
|
||||
|
||||
uint64_t CompressedVectorReaderImpl::findNextDataPacket( uint64_t nextPacketLogicalOffset )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " searching for next data packet, nextPacketLogicalOffset=" << nextPacketLogicalOffset
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " searching for next data packet, nextPacketLogicalOffset="
|
||||
<< nextPacketLogicalOffset
|
||||
<< " sectionEndLogicalOffset=" << sectionEndLogicalOffset_ << std::endl;
|
||||
#endif
|
||||
|
||||
/// Starting at nextPacketLogicalOffset, search for next data packet until
|
||||
/// hit end of binary section.
|
||||
// Starting at nextPacketLogicalOffset, search for next data packet until
|
||||
// hit end of binary section.
|
||||
while ( nextPacketLogicalOffset < sectionEndLogicalOffset_ )
|
||||
{
|
||||
char *anyPacket = nullptr;
|
||||
|
||||
std::unique_ptr<PacketLock> packetLock = cache_->lock( nextPacketLogicalOffset, anyPacket );
|
||||
std::unique_ptr<PacketLock> packetLock =
|
||||
cache_->lock( nextPacketLogicalOffset, anyPacket );
|
||||
|
||||
/// Guess it's a data packet, if not continue to next packet
|
||||
// Guess it's a data packet, if not continue to next packet
|
||||
auto dpkt = reinterpret_cast<const DataPacket *>( anyPacket );
|
||||
|
||||
if ( dpkt->header.packetType == DATA_PACKET )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " Found next data packet at nextPacketLogicalOffset=" << nextPacketLogicalOffset << std::endl;
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " Found next data packet at nextPacketLogicalOffset="
|
||||
<< nextPacketLogicalOffset << std::endl;
|
||||
#endif
|
||||
return nextPacketLogicalOffset;
|
||||
}
|
||||
|
||||
/// All packets have length in same place, so can use the field to skip to
|
||||
/// next packet.
|
||||
// All packets have length in same place, so can use the field to skip to
|
||||
// next packet.
|
||||
nextPacketLogicalOffset += dpkt->header.packetLogicalLengthMinus1 + 1;
|
||||
}
|
||||
|
||||
/// Ran off end of section, so return failure code.
|
||||
return E57_UINT64_MAX;
|
||||
// Ran off end of section, so return failure code.
|
||||
return UINT64_MAX;
|
||||
}
|
||||
|
||||
void CompressedVectorReaderImpl::seek( uint64_t /*recordNumber*/ )
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
///!!! implement
|
||||
throw E57_EXCEPTION1( E57_ERROR_NOT_IMPLEMENTED );
|
||||
// !!! implement
|
||||
throw E57_EXCEPTION1( ErrorNotImplemented );
|
||||
}
|
||||
|
||||
bool CompressedVectorReaderImpl::isOpen() const
|
||||
{
|
||||
/// don't checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__), or
|
||||
/// checkReaderOpen()
|
||||
// don't checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__), or
|
||||
// checkReaderOpen()
|
||||
return ( isOpen_ );
|
||||
}
|
||||
|
||||
std::shared_ptr<CompressedVectorNodeImpl> CompressedVectorReaderImpl::compressedVectorNode() const
|
||||
std::shared_ptr<CompressedVectorNodeImpl> CompressedVectorReaderImpl::compressedVectorNode()
|
||||
const
|
||||
{
|
||||
return ( cVector_ );
|
||||
}
|
||||
|
||||
void CompressedVectorReaderImpl::close()
|
||||
{
|
||||
/// Before anything that can throw, decrement reader count
|
||||
// Before anything that can throw, decrement reader count
|
||||
ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
|
||||
imf->decrReaderCount();
|
||||
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
/// No error if reader not open
|
||||
// No error if reader not open
|
||||
if ( !isOpen_ )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// Destroy decoders
|
||||
// Destroy decoders
|
||||
channels_.clear();
|
||||
|
||||
delete cache_;
|
||||
@@ -561,7 +590,9 @@ namespace e57
|
||||
const char *srcFunctionName ) const
|
||||
{
|
||||
// unimplemented...
|
||||
(void)srcFileName; (void)srcLineNumber; (void)srcFunctionName;
|
||||
E57_UNUSED( srcFileName );
|
||||
E57_UNUSED( srcLineNumber );
|
||||
E57_UNUSED( srcFunctionName );
|
||||
}
|
||||
|
||||
void CompressedVectorReaderImpl::checkReaderOpen( const char *srcFileName, int srcLineNumber,
|
||||
@@ -569,13 +600,14 @@ namespace e57
|
||||
{
|
||||
if ( !isOpen_ )
|
||||
{
|
||||
throw E57Exception( E57_ERROR_READER_NOT_OPEN,
|
||||
"imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName(),
|
||||
throw E57Exception( ErrorReaderNotOpen,
|
||||
"imageFileName=" + cVector_->imageFileName() +
|
||||
" cvPathName=" + cVector_->pathName(),
|
||||
srcFileName, srcLineNumber, srcFunctionName );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void CompressedVectorReaderImpl::dump( int indent, std::ostream &os )
|
||||
{
|
||||
os << space( indent ) << "isOpen:" << isOpen_ << std::endl;
|
||||
|
||||
@@ -36,8 +36,10 @@ namespace e57
|
||||
class CompressedVectorReaderImpl
|
||||
{
|
||||
public:
|
||||
CompressedVectorReaderImpl( std::shared_ptr<CompressedVectorNodeImpl> ni, std::vector<SourceDestBuffer> &dbufs );
|
||||
CompressedVectorReaderImpl( std::shared_ptr<CompressedVectorNodeImpl> cvi,
|
||||
std::vector<SourceDestBuffer> &dbufs );
|
||||
~CompressedVectorReaderImpl();
|
||||
|
||||
unsigned read();
|
||||
unsigned read( std::vector<SourceDestBuffer> &dbufs );
|
||||
void seek( uint64_t recordNumber );
|
||||
@@ -45,13 +47,15 @@ namespace e57
|
||||
std::shared_ptr<CompressedVectorNodeImpl> compressedVectorNode() const;
|
||||
void close();
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout );
|
||||
#endif
|
||||
|
||||
private:
|
||||
void checkImageFileOpen( const char *srcFileName, int srcLineNumber, const char *srcFunctionName ) const;
|
||||
void checkReaderOpen( const char *srcFileName, int srcLineNumber, const char *srcFunctionName ) const;
|
||||
void checkImageFileOpen( const char *srcFileName, int srcLineNumber,
|
||||
const char *srcFunctionName ) const;
|
||||
void checkReaderOpen( const char *srcFileName, int srcLineNumber,
|
||||
const char *srcFunctionName ) const;
|
||||
void setBuffers( std::vector<SourceDestBuffer> &dbufs ); //???needed?
|
||||
uint64_t earliestPacketNeededForInput() const;
|
||||
|
||||
|
||||
333
src/3rdParty/libE57Format/src/CompressedVectorWriter.cpp
vendored
Normal file
333
src/3rdParty/libE57Format/src/CompressedVectorWriter.cpp
vendored
Normal file
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* CompressedVectorWriter.cpp - implementation of public functions of the
|
||||
* CompressedVectorWriter class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file CompressedVectorWriter.cpp
|
||||
|
||||
#include "CompressedVectorWriterImpl.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether CompressedVectorWriter class invariant is true
|
||||
@copydetails CompressedVectorReader::checkInvariant
|
||||
*/
|
||||
void CompressedVectorWriter::checkInvariant( bool /*doRecurse*/ )
|
||||
{
|
||||
// If this CompressedVectorWriter is not open, can't test invariant (almost
|
||||
// every call would throw)
|
||||
if ( !isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CompressedVectorNode cv = compressedVectorNode();
|
||||
ImageFile imf = cv.destImageFile();
|
||||
|
||||
// If destImageFile not open, can't test invariant (almost every call would
|
||||
// throw)
|
||||
if ( !imf.isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Associated CompressedVectorNode must be attached to ImageFile
|
||||
if ( !cv.isAttached() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Dest ImageFile must be writable
|
||||
if ( !imf.isWritable() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Dest ImageFile must have exactly 1 writer (this one)
|
||||
if ( imf.writerCount() != 1 )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Dest ImageFile can't have any readers
|
||||
if ( imf.readerCount() != 0 )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::CompressedVectorWriter
|
||||
|
||||
@brief An iterator object keeping track of a write in progress to a CompressedVectorNode.
|
||||
|
||||
@details
|
||||
A CompressedVectorWriter object is a block iterator that reads blocks of records from memory and
|
||||
stores them in a CompressedVectorNode. Blocks of records are processed rather than a single
|
||||
record-at-a-time for efficiency reasons. The CompressedVectorWriter class encapsulates all the state
|
||||
that must be saved in between the processing of one record block and the next (e.g. partially
|
||||
written disk pages, partially filled bytes in a bytestream, or data compression state). New memory
|
||||
buffers can be used for each record block write, or the previous buffers can be reused.
|
||||
|
||||
CompressedVectorWriter objects have an open/closed state. Initially a newly created
|
||||
CompressedVectorWriter is in the open state. After the API user calls CompressedVectorWriter::close,
|
||||
the object will be in the closed state and no more data transfers will be possible.
|
||||
|
||||
There is no CompressedVectorWriter constructor in the API. The function CompressedVectorNode::writer
|
||||
returns an already constructed CompressedVectorWriter object with given memory buffers
|
||||
(SourceDestBuffers) already associated. CompressedVectorWriter::close must explicitly be called to
|
||||
safely and gracefully end the transfer.
|
||||
|
||||
@warning If CompressedVectorWriter::close is not called before the CompressedVectorWriter destructor
|
||||
is invoked, all writes to the CompressedVectorNode will be lost (it will have zero children).
|
||||
|
||||
@section CompressedVectorWriter_invariant Class Invariant A class invariant is a list of statements
|
||||
about an object that are always true before and after any operation on the object. An invariant is
|
||||
useful for testing correct operation of an implementation. Statements in an invariant can involve
|
||||
only externally visible state, or can refer to internal implementation-specific state that is not
|
||||
visible to the API user. The following C++ code checks externally visible state for consistency and
|
||||
throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude CompressedVectorWriter.cpp
|
||||
@skip void CompressedVectorWriter::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see CompressedVectorNode, CompressedVectorReader
|
||||
*/
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
CompressedVectorWriter::CompressedVectorWriter( std::shared_ptr<CompressedVectorWriterImpl> ni ) :
|
||||
impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
@brief Request transfer of blocks of data to CompressedVectorNode from previously designated source
|
||||
buffers.
|
||||
|
||||
@param [in] recordCount Number of records to write.
|
||||
|
||||
@details
|
||||
The SourceDestBuffers used are previously designated either in CompressedVectorNode::writer where
|
||||
this object was created, or in the last call to
|
||||
CompressedVectorWriter::write(std::vector<SourceDestBuffer>&, unsigned) where new buffers were
|
||||
designated.
|
||||
|
||||
If a conversion or bounds error occurs during the transfer, the CompressedVectorWriter is left in an
|
||||
undocumented state (it can't be used any further), and all previously written records are deleted
|
||||
from the associated CompressedVectorNode which will then have zero children. If a file I/O or
|
||||
checksum error occurs during the transfer, both this CompressedVectorWriter and the associated
|
||||
ImageFile are left in an undocumented state (they can't be used any further). If
|
||||
CompressedVectorWriter::close is not called before the CompressedVectorWriter destructor is invoked,
|
||||
all writes to the CompressedVectorNode will be lost (it will have zero children).
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
@pre This CompressedVectorWriter must be open (i.e isOpen())
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorWriterNotOpen
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorNoBufferForElement
|
||||
@throw ::ErrorBufferSizeMismatch
|
||||
@throw ::ErrorBufferDuplicatePathName
|
||||
@throw ::ErrorConversionRequired This CompressedVectorWriter in undocumented state, associated
|
||||
CompressedVectorNode modified but consistent, associated ImageFile modified but consistent.
|
||||
@throw ::ErrorValueOutOfBounds This CompressedVectorWriter in undocumented state, associated
|
||||
CompressedVectorNode modified but consistent, associated ImageFile modified but consistent.
|
||||
@throw ::ErrorValueNotRepresentable This CompressedVectorWriter in undocumented state, associated
|
||||
CompressedVectorNode modified but consistent, associated ImageFile modified but consistent.
|
||||
@throw ::ErrorScaledValueNotRepresentable This CompressedVectorWriter in undocumented state,
|
||||
associated CompressedVectorNode modified but consistent, associated ImageFile modified but
|
||||
consistent.
|
||||
@throw ::ErrorReal64TooLarge This CompressedVectorWriter in undocumented state, associated
|
||||
CompressedVectorNode modified but consistent, associated ImageFile modified but consistent.
|
||||
@throw ::ErrorExpectingNumeric This CompressedVectorWriter in undocumented state, associated
|
||||
CompressedVectorNode modified but consistent, associated ImageFile modified but consistent.
|
||||
@throw ::ErrorExpectingUString This CompressedVectorWriter in undocumented state, associated
|
||||
CompressedVectorNode modified but consistent, associated ImageFile modified but consistent.
|
||||
@throw ::ErrorSeekFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorReadFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorWriteFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorBadChecksum This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorWriter::write(std::vector<SourceDestBuffer>&,unsigned),
|
||||
CompressedVectorNode::writer, CompressedVectorWriter::close, SourceDestBuffer, E57Exception
|
||||
*/
|
||||
void CompressedVectorWriter::write( const size_t recordCount )
|
||||
{
|
||||
impl_->write( recordCount );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Request transfer of block of data to CompressedVectorNode from given source buffers.
|
||||
|
||||
@param [in] sbufs Vector of memory buffers that hold data to be written to a CompressedVectorNode.
|
||||
@param [in] recordCount Number of records to write.
|
||||
|
||||
@details
|
||||
The @a sbufs must all have the same capacity.
|
||||
|
||||
The @a sbufs capacity must be >= @a recordCount.
|
||||
|
||||
The specified @a sbufs must have same number of elements as previously designated SourceDestBuffer
|
||||
vector. The each SourceDestBuffer within @a sbufs must be identical to the previously designated
|
||||
SourceDestBuffer except for capacity and buffer address.
|
||||
|
||||
The @a sbufs locations are saved so that a later call to CompressedVectorWriter::write(unsigned) can
|
||||
be used without having to re-specify the SourceDestBuffers.
|
||||
|
||||
If a conversion or bounds error occurs during the transfer, the CompressedVectorWriter is left in an
|
||||
undocumented state (it can't be used any further), and all previously written records are deleted
|
||||
from the the associated CompressedVectorNode which will then have zero children. If a file I/O or
|
||||
checksum error occurs during the transfer, both this CompressedVectorWriter and the associated
|
||||
ImageFile are left in an undocumented state (they can't be used any further).
|
||||
|
||||
@warning If CompressedVectorWriter::close is not called before the CompressedVectorWriter destructor
|
||||
is invoked, all writes to the CompressedVectorNode will be lost (it will have zero children).
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
@pre This CompressedVectorWriter must be open (i.e isOpen())
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorWriterNotOpen
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorNoBufferForElement
|
||||
@throw ::ErrorBufferSizeMismatch
|
||||
@throw ::ErrorBufferDuplicatePathName
|
||||
@throw ::ErrorConversionRequired This CompressedVectorWriter in undocumented state, associated
|
||||
ImageFile modified but consistent.
|
||||
@throw ::ErrorValueOutOfBounds This CompressedVectorWriter in undocumented state, associated
|
||||
ImageFile modified but consistent.
|
||||
@throw ::ErrorValueNotRepresentable This CompressedVectorWriter in undocumented state, associated
|
||||
ImageFile modified but consistent.
|
||||
@throw ::ErrorScaledValueNotRepresentable This CompressedVectorWriter in undocumented state,
|
||||
associated ImageFile modified but consistent.
|
||||
@throw ::ErrorReal64TooLarge This CompressedVectorWriter in undocumented state, associated ImageFile
|
||||
modified but consistent.
|
||||
@throw ::ErrorExpectingNumeric This CompressedVectorWriter in undocumented state, associated
|
||||
ImageFile modified but consistent.
|
||||
@throw ::ErrorExpectingUString This CompressedVectorWriter in undocumented state, associated
|
||||
ImageFile modified but consistent.
|
||||
@throw ::ErrorSeekFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorReadFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorWriteFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorBadChecksum This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorWriter::write(unsigned), CompressedVectorNode::writer,
|
||||
CompressedVectorWriter::close, SourceDestBuffer, E57Exception
|
||||
*/
|
||||
void CompressedVectorWriter::write( std::vector<SourceDestBuffer> &sbufs, const size_t recordCount )
|
||||
{
|
||||
impl_->write( sbufs, recordCount );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief End the write operation.
|
||||
|
||||
@details
|
||||
This function must be called to safely and gracefully end a transfer to a CompressedVectorNode. This
|
||||
is required because errors cannot be communicated from the CompressedVectorNode destructor (in C++
|
||||
destructors can't throw exceptions). It is not an error to call this function if the
|
||||
CompressedVectorWriter is already closed. This function will cause the CompressedVectorWriter to
|
||||
enter the closed state, and any further transfers requests will fail.
|
||||
|
||||
@warning If this function is not called before the CompressedVectorWriter destructor is invoked, all
|
||||
writes to the CompressedVectorNode will be lost (it will have zero children).
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
@post This CompressedVectorWriter is closed (i.e !isOpen())
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorSeekFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorReadFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorWriteFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorBadChecksum This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorWriter::isOpen
|
||||
*/
|
||||
void CompressedVectorWriter::close()
|
||||
{
|
||||
impl_->close();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Test whether CompressedVectorWriter is still open for writing.
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorWriter::close, CompressedVectorNode::writer
|
||||
*/
|
||||
bool CompressedVectorWriter::isOpen()
|
||||
{
|
||||
return impl_->isOpen();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return the CompressedVectorNode being written to.
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
|
||||
@return A smart CompressedVectorNode handle referencing the underlying object being written to.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::writer
|
||||
*/
|
||||
CompressedVectorNode CompressedVectorWriter::compressedVectorNode() const
|
||||
{
|
||||
return impl_->compressedVectorNode();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void CompressedVectorWriter::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void CompressedVectorWriter::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
@@ -34,84 +34,87 @@
|
||||
#include "ImageFileImpl.h"
|
||||
#include "SectionHeaders.h"
|
||||
#include "SourceDestBufferImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
struct SortByBytestreamNumber
|
||||
{
|
||||
bool operator()( const std::shared_ptr<Encoder> &lhs, const std::shared_ptr<Encoder> &rhs ) const
|
||||
bool operator()( const std::shared_ptr<Encoder> &lhs,
|
||||
const std::shared_ptr<Encoder> &rhs ) const
|
||||
{
|
||||
return ( lhs->bytestreamNumber() < rhs->bytestreamNumber() );
|
||||
}
|
||||
};
|
||||
|
||||
CompressedVectorWriterImpl::CompressedVectorWriterImpl( std::shared_ptr<CompressedVectorNodeImpl> ni,
|
||||
std::vector<SourceDestBuffer> &sbufs ) :
|
||||
cVector_( ni ),
|
||||
isOpen_( false ) // set to true when succeed below
|
||||
CompressedVectorWriterImpl::CompressedVectorWriterImpl(
|
||||
std::shared_ptr<CompressedVectorNodeImpl> ni, std::vector<SourceDestBuffer> &sbufs ) :
|
||||
cVector_( ni ), isOpen_( false ) // set to true when succeed below
|
||||
{
|
||||
//??? check if cvector already been written (can't write twice)
|
||||
|
||||
/// Empty sbufs is an error
|
||||
// Empty sbufs is an error
|
||||
if ( sbufs.empty() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT,
|
||||
"imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorBadAPIArgument, "imageFileName=" + cVector_->imageFileName() +
|
||||
" cvPathName=" + cVector_->pathName() );
|
||||
}
|
||||
|
||||
/// Get CompressedArray's prototype node (all array elements must match this
|
||||
/// type)
|
||||
// Get CompressedArray's prototype node (all array elements must match this
|
||||
// type)
|
||||
proto_ = cVector_->getPrototype();
|
||||
|
||||
/// Check sbufs well formed (matches proto exactly)
|
||||
// Check sbufs well formed (matches proto exactly)
|
||||
setBuffers( sbufs ); //??? copy code here?
|
||||
|
||||
/// For each individual sbuf, create an appropriate Encoder based on the
|
||||
/// cVector_ attributes
|
||||
// For each individual sbuf, create an appropriate Encoder based on the
|
||||
// cVector_ attributes
|
||||
for ( unsigned i = 0; i < sbufs_.size(); i++ )
|
||||
{
|
||||
/// Create vector of single sbuf ??? for now, may have groups later
|
||||
// Create vector of single sbuf ??? for now, may have groups later
|
||||
std::vector<SourceDestBuffer> vTemp;
|
||||
vTemp.push_back( sbufs_.at( i ) );
|
||||
|
||||
ustring codecPath = sbufs_.at( i ).pathName();
|
||||
|
||||
/// Calc which stream the given path belongs to. This depends on position
|
||||
/// of the node in the proto tree.
|
||||
// Calc which stream the given path belongs to. This depends on position
|
||||
// of the node in the proto tree.
|
||||
NodeImplSharedPtr readNode = proto_->get( sbufs.at( i ).pathName() );
|
||||
uint64_t bytestreamNumber = 0;
|
||||
if ( !proto_->findTerminalPosition( readNode, bytestreamNumber ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "sbufIndex=" + toString( i ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "sbufIndex=" + toString( i ) );
|
||||
}
|
||||
|
||||
/// EncoderFactory picks the appropriate encoder to match type declared in
|
||||
/// prototype
|
||||
bytestreams_.push_back(
|
||||
Encoder::EncoderFactory( static_cast<unsigned>( bytestreamNumber ), cVector_, vTemp, codecPath ) );
|
||||
// EncoderFactory picks the appropriate encoder to match type declared in
|
||||
// prototype
|
||||
bytestreams_.push_back( Encoder::EncoderFactory( static_cast<unsigned>( bytestreamNumber ),
|
||||
cVector_, vTemp, codecPath ) );
|
||||
}
|
||||
|
||||
/// The bytestreams_ vector must be ordered by bytestreamNumber, not by order
|
||||
/// called specified sbufs, so sort it.
|
||||
// The bytestreams_ vector must be ordered by bytestreamNumber, not by order
|
||||
// called specified sbufs, so sort it.
|
||||
sort( bytestreams_.begin(), bytestreams_.end(), SortByBytestreamNumber() );
|
||||
#ifdef E57_MAX_DEBUG
|
||||
/// Double check that all bytestreams are specified
|
||||
#if ( E57_VALIDATION_LEVEL == VALIDATION_DEEP )
|
||||
// Double check that all bytestreams are specified
|
||||
for ( unsigned i = 0; i < bytestreams_.size(); i++ )
|
||||
{
|
||||
if ( bytestreams_.at( i )->bytestreamNumber() != i )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "bytestreamIndex=" + toString( i ) + " bytestreamNumber=" +
|
||||
toString( bytestreams_.at( i )->bytestreamNumber() ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal,
|
||||
"bytestreamIndex=" + toString( i ) + " bytestreamNumber=" +
|
||||
toString( bytestreams_.at( i )->bytestreamNumber() ) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ImageFileImplSharedPtr imf( ni->destImageFile_ );
|
||||
|
||||
/// Reserve space for CompressedVector binary section header, record location
|
||||
/// so can save to when writer closes. Request that file be extended with
|
||||
/// zeros since we will write to it at a later time (when writer closes).
|
||||
sectionHeaderLogicalStart_ = imf->allocateSpace( sizeof( CompressedVectorSectionHeader ), true );
|
||||
// Reserve space for CompressedVector binary section header, record location
|
||||
// so can save to when writer closes. Request that file be extended with
|
||||
// zeros since we will write to it at a later time (when writer closes).
|
||||
sectionHeaderLogicalStart_ =
|
||||
imf->allocateSpace( sizeof( CompressedVectorSectionHeader ), true );
|
||||
|
||||
sectionLogicalLength_ = 0;
|
||||
dataPhysicalOffset_ = 0;
|
||||
@@ -120,17 +123,17 @@ namespace e57
|
||||
dataPacketsCount_ = 0;
|
||||
indexPacketsCount_ = 0;
|
||||
|
||||
/// Just before return (and can't throw) increment writer count ??? safer
|
||||
/// way to assure don't miss close?
|
||||
// Just before return (and can't throw) increment writer count ??? safer
|
||||
// way to assure don't miss close?
|
||||
imf->incrWriterCount();
|
||||
|
||||
/// If get here, the writer is open
|
||||
// If get here, the writer is open
|
||||
isOpen_ = true;
|
||||
}
|
||||
|
||||
CompressedVectorWriterImpl::~CompressedVectorWriterImpl()
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "~CompressedVectorWriterImpl() called" << std::endl; //???
|
||||
#endif
|
||||
|
||||
@@ -149,30 +152,30 @@ namespace e57
|
||||
|
||||
void CompressedVectorWriterImpl::close()
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "CompressedVectorWriterImpl::close() called" << std::endl; //???
|
||||
#endif
|
||||
ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
|
||||
|
||||
/// Before anything that can throw, decrement writer count
|
||||
// Before anything that can throw, decrement writer count
|
||||
imf->decrWriterCount();
|
||||
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
/// don't call checkWriterOpen();
|
||||
// don't call checkWriterOpen();
|
||||
|
||||
if ( !isOpen_ )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// Set closed before do anything, so if get fault and start unwinding, don't
|
||||
/// try to close again.
|
||||
// Set closed before do anything, so if get fault and start unwinding, don't
|
||||
// try to close again.
|
||||
isOpen_ = false;
|
||||
|
||||
/// If have any data, write packet
|
||||
/// Write all remaining ioBuffers and internal encoder register cache into
|
||||
/// file. Know we are done when totalOutputAvailable() returns 0 after a
|
||||
/// flush().
|
||||
// If have any data, write packet
|
||||
// Write all remaining ioBuffers and internal encoder register cache into
|
||||
// file. Know we are done when totalOutputAvailable() returns 0 after a
|
||||
// flush().
|
||||
flush();
|
||||
while ( totalOutputAvailable() > 0 )
|
||||
{
|
||||
@@ -180,40 +183,46 @@ namespace e57
|
||||
flush();
|
||||
}
|
||||
|
||||
/// Compute length of whole section we just wrote (from section start to
|
||||
/// current start of free space).
|
||||
// Write one index packet (required by standard).
|
||||
packetWriteIndex();
|
||||
|
||||
// Compute length of whole section we just wrote (from section start to
|
||||
// current start of free space).
|
||||
sectionLogicalLength_ = imf->unusedLogicalStart_ - sectionHeaderLogicalStart_;
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " sectionLogicalLength_=" << sectionLogicalLength_ << std::endl; //???
|
||||
#endif
|
||||
|
||||
/// Prepare CompressedVectorSectionHeader
|
||||
// Prepare CompressedVectorSectionHeader
|
||||
CompressedVectorSectionHeader header;
|
||||
header.sectionLogicalLength = sectionLogicalLength_;
|
||||
header.dataPhysicalOffset = dataPhysicalOffset_; ///??? can be zero, if no data written ???not set yet
|
||||
header.indexPhysicalOffset = topIndexPhysicalOffset_; ///??? can be zero, if no data written ???not set
|
||||
/// yet
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
header.dataPhysicalOffset =
|
||||
dataPhysicalOffset_; //??? can be zero, if no data written ???not set yet
|
||||
header.indexPhysicalOffset =
|
||||
topIndexPhysicalOffset_; //??? can be zero, if no data written ???not set
|
||||
// yet
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " CompressedVectorSectionHeader:" << std::endl;
|
||||
header.dump( 4 ); //???
|
||||
#endif
|
||||
#ifdef E57_DEBUG
|
||||
/// Verify OK before write it.
|
||||
|
||||
#if VALIDATE_BASIC
|
||||
// Verify OK before write it.
|
||||
header.verify( imf->file_->length( CheckedFile::Physical ) );
|
||||
#endif
|
||||
|
||||
/// Write header at beginning of section, previously allocated
|
||||
// Write header at beginning of section, previously allocated
|
||||
imf->file_->seek( sectionHeaderLogicalStart_ );
|
||||
imf->file_->write( reinterpret_cast<char *>( &header ), sizeof( header ) );
|
||||
|
||||
/// Set address and size of associated CompressedVector
|
||||
// Set address and size of associated CompressedVector
|
||||
cVector_->setRecordCount( recordCount_ );
|
||||
cVector_->setBinarySectionLogicalStart( sectionHeaderLogicalStart_ );
|
||||
|
||||
/// Free channels
|
||||
// Free channels
|
||||
bytestreams_.clear();
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " CompressedVectorWriter:" << std::endl;
|
||||
dump( 4 );
|
||||
#endif
|
||||
@@ -221,28 +230,30 @@ namespace e57
|
||||
|
||||
bool CompressedVectorWriterImpl::isOpen() const
|
||||
{
|
||||
/// don't checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__), or
|
||||
/// checkWriterOpen()
|
||||
// don't checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__), or
|
||||
// checkWriterOpen()
|
||||
return isOpen_;
|
||||
}
|
||||
|
||||
std::shared_ptr<CompressedVectorNodeImpl> CompressedVectorWriterImpl::compressedVectorNode() const
|
||||
std::shared_ptr<CompressedVectorNodeImpl> CompressedVectorWriterImpl::compressedVectorNode()
|
||||
const
|
||||
{
|
||||
return cVector_;
|
||||
}
|
||||
|
||||
void CompressedVectorWriterImpl::setBuffers( std::vector<SourceDestBuffer> &sbufs )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// If had previous sbufs_, check to see if new ones have changed in
|
||||
/// incompatible way
|
||||
// If had previous sbufs_, check to see if new ones have changed in
|
||||
// incompatible way
|
||||
if ( !sbufs_.empty() )
|
||||
{
|
||||
if ( sbufs_.size() != sbufs.size() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BUFFERS_NOT_COMPATIBLE,
|
||||
"oldSize=" + toString( sbufs_.size() ) + " newSize=" + toString( sbufs.size() ) );
|
||||
throw E57_EXCEPTION2( ErrorBuffersNotCompatible,
|
||||
"oldSize=" + toString( sbufs_.size() ) +
|
||||
" newSize=" + toString( sbufs.size() ) );
|
||||
}
|
||||
|
||||
for ( size_t i = 0; i < sbufs_.size(); ++i )
|
||||
@@ -250,23 +261,24 @@ namespace e57
|
||||
std::shared_ptr<SourceDestBufferImpl> oldbuf = sbufs_[i].impl();
|
||||
std::shared_ptr<SourceDestBufferImpl> newBuf = sbufs[i].impl();
|
||||
|
||||
/// Throw exception if old and new not compatible
|
||||
// Throw exception if old and new not compatible
|
||||
oldbuf->checkCompatible( newBuf );
|
||||
}
|
||||
}
|
||||
|
||||
/// Check sbufs well formed: no dups, no missing, no extra
|
||||
/// For writing, all data fields in prototype must be presented for writing
|
||||
/// at same time.
|
||||
// Check sbufs well formed: no dups, no missing, no extra
|
||||
// For writing, all data fields in prototype must be presented for writing
|
||||
// at same time.
|
||||
proto_->checkBuffers( sbufs, false );
|
||||
|
||||
sbufs_ = sbufs;
|
||||
}
|
||||
|
||||
void CompressedVectorWriterImpl::write( std::vector<SourceDestBuffer> &sbufs, const size_t requestedRecordCount )
|
||||
void CompressedVectorWriterImpl::write( std::vector<SourceDestBuffer> &sbufs,
|
||||
const size_t requestedRecordCount )
|
||||
{
|
||||
/// don't checkImageFileOpen, write(unsigned) will do it
|
||||
/// don't checkWriterOpen(), write(unsigned) will do it
|
||||
// don't checkImageFileOpen, write(unsigned) will do it
|
||||
// don't checkWriterOpen(), write(unsigned) will do it
|
||||
|
||||
setBuffers( sbufs );
|
||||
write( requestedRecordCount );
|
||||
@@ -274,78 +286,85 @@ namespace e57
|
||||
|
||||
void CompressedVectorWriterImpl::write( const size_t requestedRecordCount )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "CompressedVectorWriterImpl::write() called" << std::endl; //???
|
||||
#endif
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
checkWriterOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
/// Check that requestedRecordCount is not larger than the sbufs
|
||||
if ( requestedRecordCount > sbufs_.at( 0 ).impl()->capacity() )
|
||||
if ( requestedRecordCount == 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT,
|
||||
"requested=" + toString( requestedRecordCount ) +
|
||||
" capacity=" + toString( sbufs_.at( 0 ).impl()->capacity() ) + " imageFileName=" +
|
||||
cVector_->imageFileName() + " cvPathName=" + cVector_->pathName() );
|
||||
packetWriteZeroRecords();
|
||||
return;
|
||||
}
|
||||
|
||||
/// Rewind all sbufs so start reading from beginning
|
||||
// Check that requestedRecordCount is not larger than the sbufs
|
||||
if ( requestedRecordCount > sbufs_.at( 0 ).impl()->capacity() )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadAPIArgument,
|
||||
"requested=" + toString( requestedRecordCount ) +
|
||||
" capacity=" + toString( sbufs_.at( 0 ).impl()->capacity() ) +
|
||||
" imageFileName=" + cVector_->imageFileName() +
|
||||
" cvPathName=" + cVector_->pathName() );
|
||||
}
|
||||
|
||||
// Rewind all sbufs so start reading from beginning
|
||||
for ( auto &sbuf : sbufs_ )
|
||||
{
|
||||
sbuf.impl()->rewind();
|
||||
}
|
||||
|
||||
/// Loop until all channels have completed requestedRecordCount transfers
|
||||
// Loop until all channels have completed requestedRecordCount transfers
|
||||
uint64_t endRecordIndex = recordCount_ + requestedRecordCount;
|
||||
while ( true )
|
||||
{
|
||||
/// Calc remaining record counts for all channels
|
||||
// Calc remaining record counts for all channels
|
||||
uint64_t totalRecordCount = 0;
|
||||
for ( auto &bytestream : bytestreams_ )
|
||||
{
|
||||
totalRecordCount += endRecordIndex - bytestream->currentRecordIndex();
|
||||
}
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " totalRecordCount=" << totalRecordCount << std::endl; //???
|
||||
#endif
|
||||
|
||||
/// We are done if have no more work, break out of loop
|
||||
// We are done if have no more work, break out of loop
|
||||
if ( totalRecordCount == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/// Estimate how many records can write before have enough data to fill
|
||||
/// data packet to efficient length Efficient packet length is >= 75%
|
||||
/// of maximum packet length. It is OK if get too much data (more than
|
||||
/// one packet) in an iteration. Reader will be able to handle packets
|
||||
/// whose streams are not exactly synchronized to the record
|
||||
/// boundaries. But try to do a good job of keeping the stream
|
||||
/// synchronization "close enough" (so a reader that can cache only two
|
||||
/// packets is efficient).
|
||||
// Estimate how many records can write before have enough data to fill
|
||||
// data packet to efficient length Efficient packet length is >= 75%
|
||||
// of maximum packet length. It is OK if get too much data (more than
|
||||
// one packet) in an iteration. Reader will be able to handle packets
|
||||
// whose streams are not exactly synchronized to the record
|
||||
// boundaries. But try to do a good job of keeping the stream
|
||||
// synchronization "close enough" (so a reader that can cache only two
|
||||
// packets is efficient).
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " currentPacketSize()=" << currentPacketSize() << std::endl; //???
|
||||
#endif
|
||||
|
||||
#ifdef E57_WRITE_CRAZY_PACKET_MODE
|
||||
///??? depends on number of streams
|
||||
//??? depends on number of streams
|
||||
constexpr size_t E57_TARGET_PACKET_SIZE = 500;
|
||||
#else
|
||||
constexpr size_t E57_TARGET_PACKET_SIZE = ( DATA_PACKET_MAX * 3 / 4 );
|
||||
#endif
|
||||
/// If have more than target fraction of packet, send it now
|
||||
// If have more than target fraction of packet, send it now
|
||||
if ( currentPacketSize() >= E57_TARGET_PACKET_SIZE )
|
||||
{ //???
|
||||
packetWrite();
|
||||
continue; /// restart loop so recalc statistics (packet size may not be
|
||||
/// zero after write, if have too much data)
|
||||
continue; // restart loop so recalc statistics (packet size may not be
|
||||
// zero after write, if have too much data)
|
||||
}
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
///??? useful?
|
||||
/// Get approximation of number of bytes per record of CompressedVector
|
||||
/// and total of bytes used
|
||||
#ifdef E57_VERBOSE
|
||||
//??? useful?
|
||||
// Get approximation of number of bytes per record of CompressedVector
|
||||
// and total of bytes used
|
||||
float totalBitsPerRecord = 0; // an estimate of future performance
|
||||
for ( auto &bytestream : bytestreams_ )
|
||||
{
|
||||
@@ -357,19 +376,20 @@ namespace e57
|
||||
std::cout << " totalBytesPerRecord=" << totalBytesPerRecord << std::endl; //???
|
||||
#endif
|
||||
|
||||
/// Don't allow straggler to get too far behind. ???
|
||||
/// Don't allow a single channel to get too far ahead ???
|
||||
/// Process channels that are furthest behind first. ???
|
||||
// Don't allow straggler to get too far behind. ???
|
||||
// Don't allow a single channel to get too far ahead ???
|
||||
// Process channels that are furthest behind first. ???
|
||||
|
||||
///!!!! For now just process one record per loop until packet is full
|
||||
/// enough, or completed request
|
||||
// !!!! For now just process one record per loop until packet is full
|
||||
// enough, or completed request
|
||||
for ( auto &bytestream : bytestreams_ )
|
||||
{
|
||||
if ( bytestream->currentRecordIndex() < endRecordIndex )
|
||||
{
|
||||
//!!! For now, process up to 50 records at a time
|
||||
// !!! For now, process up to 50 records at a time
|
||||
uint64_t recordCount = endRecordIndex - bytestream->currentRecordIndex();
|
||||
recordCount = ( recordCount < 50ULL ) ? recordCount : 50ULL; // min(recordCount, 50ULL);
|
||||
recordCount =
|
||||
( recordCount < 50ULL ) ? recordCount : 50ULL; // min(recordCount, 50ULL);
|
||||
bytestream->processRecords( static_cast<unsigned>( recordCount ) );
|
||||
}
|
||||
}
|
||||
@@ -377,8 +397,8 @@ namespace e57
|
||||
|
||||
recordCount_ += requestedRecordCount;
|
||||
|
||||
/// When we leave this function, will likely still have data in channel
|
||||
/// ioBuffers as well as partial words in Encoder registers.
|
||||
// When we leave this function, will likely still have data in channel
|
||||
// ioBuffers as well as partial words in Encoder registers.
|
||||
}
|
||||
|
||||
size_t CompressedVectorWriterImpl::totalOutputAvailable() const
|
||||
@@ -395,200 +415,279 @@ namespace e57
|
||||
|
||||
size_t CompressedVectorWriterImpl::currentPacketSize() const
|
||||
{
|
||||
/// Calc current packet size
|
||||
return ( sizeof( DataPacketHeader ) + bytestreams_.size() * sizeof( uint16_t ) + totalOutputAvailable() );
|
||||
// Calc current packet size
|
||||
return ( sizeof( DataPacketHeader ) + bytestreams_.size() * sizeof( uint16_t ) +
|
||||
totalOutputAvailable() );
|
||||
}
|
||||
|
||||
uint64_t CompressedVectorWriterImpl::packetWrite()
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "CompressedVectorWriterImpl::packetWrite() called" << std::endl; //???
|
||||
#endif
|
||||
|
||||
/// Double check that we have work to do
|
||||
size_t totalOutput = totalOutputAvailable();
|
||||
if ( totalOutput == 0 )
|
||||
// Double check that we have work to do
|
||||
const size_t cTotalOutput = totalOutputAvailable();
|
||||
if ( cTotalOutput == 0 )
|
||||
{
|
||||
return ( 0 );
|
||||
}
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " totalOutput=" << totalOutput << std::endl; //???
|
||||
|
||||
// const bytestreams_ so it's clear it isn't modified in this function
|
||||
const auto &cStreams = bytestreams_;
|
||||
const auto cNumByteStreams = cStreams.size();
|
||||
|
||||
// Calc maximum number of bytestream values can put in data packet.
|
||||
const size_t cPacketMaxPayloadBytes =
|
||||
DATA_PACKET_MAX - sizeof( DataPacketHeader ) - cNumByteStreams * sizeof( uint16_t );
|
||||
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " totalOutput=" << cTotalOutput << std::endl;
|
||||
std::cout << " cNumByteStreams=" << cNumByteStreams << std::endl;
|
||||
std::cout << " packetMaxPayloadBytes=" << cPacketMaxPayloadBytes << std::endl;
|
||||
#endif
|
||||
|
||||
/// Calc maximum number of bytestream values can put in data packet.
|
||||
size_t packetMaxPayloadBytes =
|
||||
DATA_PACKET_MAX - sizeof( DataPacketHeader ) - bytestreams_.size() * sizeof( uint16_t );
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " packetMaxPayloadBytes=" << packetMaxPayloadBytes << std::endl; //???
|
||||
#endif
|
||||
// Allocate vector for number of bytes that each bytestream will write to file.
|
||||
std::vector<size_t> count( cNumByteStreams );
|
||||
|
||||
/// Allocate vector for number of bytes that each bytestream will write to
|
||||
/// file.
|
||||
std::vector<size_t> count( bytestreams_.size() );
|
||||
|
||||
/// See if we can fit into a single data packet
|
||||
if ( totalOutput < packetMaxPayloadBytes )
|
||||
// See if we can fit into a single data packet
|
||||
if ( cTotalOutput < cPacketMaxPayloadBytes )
|
||||
{
|
||||
/// We can fit everything in one packet
|
||||
for ( unsigned i = 0; i < bytestreams_.size(); i++ )
|
||||
// We can fit everything in one packet
|
||||
for ( unsigned i = 0; i < cNumByteStreams; ++i )
|
||||
{
|
||||
count.at( i ) = bytestreams_.at( i )->outputAvailable();
|
||||
count.at( i ) = cStreams.at( i )->outputAvailable();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/// We have too much data for one packet. Send proportional amounts from
|
||||
/// each bytestream. Adjust packetMaxPayloadBytes down by one so have a
|
||||
/// little slack for floating point weirdness.
|
||||
float fractionToSend = ( packetMaxPayloadBytes - 1 ) / static_cast<float>( totalOutput );
|
||||
for ( unsigned i = 0; i < bytestreams_.size(); i++ )
|
||||
// We have too much data for one packet. Send proportional amounts from
|
||||
// each bytestream. Adjust packetMaxPayloadBytes down by one so have a
|
||||
// little slack for floating point weirdness.
|
||||
const float cFractionToSend =
|
||||
( cPacketMaxPayloadBytes - 1 ) / static_cast<float>( cTotalOutput );
|
||||
for ( unsigned i = 0; i < cNumByteStreams; ++i )
|
||||
{
|
||||
/// Round down here so sum <= packetMaxPayloadBytes
|
||||
count.at( i ) =
|
||||
static_cast<unsigned>( std::floor( fractionToSend * bytestreams_.at( i )->outputAvailable() ) );
|
||||
// Round down here so sum <= packetMaxPayloadBytes
|
||||
count.at( i ) = static_cast<unsigned>(
|
||||
std::floor( cFractionToSend * cStreams.at( i )->outputAvailable() ) );
|
||||
}
|
||||
}
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
for ( unsigned i = 0; i < bytestreams_.size(); i++ )
|
||||
|
||||
#ifdef E57_VERBOSE
|
||||
for ( unsigned i = 0; i < cNumByteStreams; ++i )
|
||||
{
|
||||
std::cout << " count[" << i << "]=" << count.at( i ) << std::endl; //???
|
||||
std::cout << " count[" << i << "]=" << count.at( i ) << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
/// Double check sum of count is <= packetMaxPayloadBytes
|
||||
const size_t totalByteCount = std::accumulate( count.begin(), count.end(), 0 );
|
||||
#if VALIDATE_BASIC
|
||||
// Double check sum of count is <= packetMaxPayloadBytes
|
||||
const size_t cTotalByteCount =
|
||||
std::accumulate( count.begin(), count.end(), static_cast<size_t>( 0 ) );
|
||||
|
||||
if ( totalByteCount > packetMaxPayloadBytes )
|
||||
if ( cTotalByteCount > cPacketMaxPayloadBytes )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "totalByteCount=" + toString( totalByteCount ) +
|
||||
" packetMaxPayloadBytes=" + toString( packetMaxPayloadBytes ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal,
|
||||
"totalByteCount=" + toString( cTotalByteCount ) +
|
||||
" packetMaxPayloadBytes=" + toString( cPacketMaxPayloadBytes ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Get smart pointer to ImageFileImpl from associated CompressedVector
|
||||
// Get smart pointer to ImageFileImpl from associated CompressedVector
|
||||
ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
|
||||
|
||||
/// Use temp buf in object (is 64KBytes long) instead of allocating each time
|
||||
/// here
|
||||
// Use temp buf in object (is 64KBytes long) instead of allocating each time here
|
||||
char *packet = reinterpret_cast<char *>( &dataPacket_ );
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " packet=" << packet << std::endl; //???
|
||||
#endif
|
||||
|
||||
/// To be safe, clear header part of packet
|
||||
// To be safe, clear header part of packet
|
||||
dataPacket_.header.reset();
|
||||
|
||||
/// Write bytestreamBufferLength[bytestreamCount] after header, in
|
||||
/// dataPacket_
|
||||
// Write bytestreamBufferLength[bytestreamCount] after header, in dataPacket_
|
||||
auto bsbLength = reinterpret_cast<uint16_t *>( &packet[sizeof( DataPacketHeader )] );
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " bsbLength=" << bsbLength << std::endl; //???
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " packet=" << static_cast<void *>( packet ) << std::endl; //???
|
||||
std::cout << " bsbLength=" << bsbLength << std::endl; //???
|
||||
#endif
|
||||
for ( unsigned i = 0; i < bytestreams_.size(); i++ )
|
||||
for ( unsigned i = 0; i < cNumByteStreams; ++i )
|
||||
{
|
||||
bsbLength[i] = static_cast<uint16_t>( count.at( i ) ); // %%% Truncation
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " Writing " << bsbLength[i] << " bytes into bytestream " << i << std::endl; //???
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " Writing " << bsbLength[i] << " bytes into bytestream " << i
|
||||
<< std::endl; //???
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Get pointer to end of data so far
|
||||
char *p = reinterpret_cast<char *>( &bsbLength[bytestreams_.size()] );
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " after bsbLength, p=" << p << std::endl; //???
|
||||
// Get pointer to end of data so far
|
||||
auto *p = reinterpret_cast<char *>( &bsbLength[cNumByteStreams] );
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " after bsbLength, p=" << static_cast<void *>( p ) << std::endl; //???
|
||||
#endif
|
||||
|
||||
/// Write contents of each bytestream in dataPacket_
|
||||
for ( size_t i = 0; i < bytestreams_.size(); i++ )
|
||||
// Write contents of each bytestream in dataPacket_
|
||||
for ( size_t i = 0; i < cNumByteStreams; ++i )
|
||||
{
|
||||
size_t n = count.at( i );
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
/// Double check we aren't accidentally going to write off end of
|
||||
/// vector<char>
|
||||
#if VALIDATE_BASIC
|
||||
// Double check we aren't accidentally going to write off end of vector<char>
|
||||
if ( &p[n] > &packet[DATA_PACKET_MAX] )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "n=" + toString( n ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "n=" + toString( n ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Read from encoder output into packet
|
||||
bytestreams_.at( i )->outputRead( p, n );
|
||||
// Read from encoder output into packet
|
||||
cStreams.at( i )->outputRead( p, n );
|
||||
|
||||
/// Move pointer to end of current data
|
||||
// Move pointer to end of current data
|
||||
p += n;
|
||||
}
|
||||
|
||||
/// Length of packet is difference in beginning pointer and ending pointer
|
||||
auto packetLength = static_cast<unsigned>( p - packet ); ///??? pointer diff portable?
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
// Length of packet is difference in beginning pointer and ending pointer
|
||||
auto packetLength = static_cast<unsigned>( p - packet ); //??? pointer diff portable?
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " packetLength=" << packetLength << std::endl; //???
|
||||
#endif
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
/// Double check that packetLength is what we expect
|
||||
if ( packetLength != sizeof( DataPacketHeader ) + bytestreams_.size() * sizeof( uint16_t ) + totalByteCount )
|
||||
#if VALIDATE_BASIC
|
||||
// Double check that packetLength is what we expect
|
||||
if ( packetLength !=
|
||||
sizeof( DataPacketHeader ) + cNumByteStreams * sizeof( uint16_t ) + cTotalByteCount )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetLength=" + toString( packetLength ) + " bytestreamSize=" +
|
||||
toString( bytestreams_.size() * sizeof( uint16_t ) ) +
|
||||
" totalByteCount=" + toString( totalByteCount ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "packetLength=" + toString( packetLength ) +
|
||||
" bytestreamSize=" +
|
||||
toString( cNumByteStreams * sizeof( uint16_t ) ) +
|
||||
" totalByteCount=" + toString( cTotalByteCount ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
/// packetLength must be multiple of 4, if not, add some zero padding
|
||||
// packetLength must be multiple of 4, if not, add some zero padding
|
||||
while ( packetLength % 4 )
|
||||
{
|
||||
/// Double check we aren't accidentally going to write off end of
|
||||
/// vector<char>
|
||||
// Double check we aren't accidentally going to write off end of
|
||||
// vector<char>
|
||||
if ( p >= &packet[DATA_PACKET_MAX - 1] )
|
||||
{
|
||||
throw E57_EXCEPTION1( E57_ERROR_INTERNAL );
|
||||
throw E57_EXCEPTION1( ErrorInternal );
|
||||
}
|
||||
*p++ = 0;
|
||||
packetLength++;
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << " padding with zero byte, new packetLength=" << packetLength << std::endl; //???
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " padding with zero byte, new packetLength=" << packetLength
|
||||
<< std::endl; //???
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Prepare header in dataPacket_, now that we are sure of packetLength
|
||||
dataPacket_.header.packetLogicalLengthMinus1 = static_cast<uint16_t>( packetLength - 1 ); // %%% Truncation
|
||||
dataPacket_.header.bytestreamCount = static_cast<uint16_t>( bytestreams_.size() ); // %%% Truncation
|
||||
// Prepare header in dataPacket_, now that we are sure of packetLength
|
||||
dataPacket_.header.packetLogicalLengthMinus1 =
|
||||
static_cast<uint16_t>( packetLength - 1 ); // %%% Truncation
|
||||
dataPacket_.header.bytestreamCount =
|
||||
static_cast<uint16_t>( cNumByteStreams ); // %%% Truncation
|
||||
|
||||
/// Double check that data packet is well formed
|
||||
// Double check that data packet is well formed
|
||||
dataPacket_.verify( packetLength );
|
||||
|
||||
/// Write whole data packet at beginning of free space in file
|
||||
// Write whole data packet at beginning of free space in file
|
||||
uint64_t packetLogicalOffset = imf->allocateSpace( packetLength, false );
|
||||
uint64_t packetPhysicalOffset = imf->file_->logicalToPhysical( packetLogicalOffset );
|
||||
imf->file_->seek( packetLogicalOffset ); //??? have seekLogical and seekPhysical instead?
|
||||
// more explicit
|
||||
imf->file_->write( packet, packetLength );
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
// std::cout << "data packet:" << std::endl;
|
||||
// dataPacket_.dump(4);
|
||||
#endif
|
||||
|
||||
/// If first data packet written for this CompressedVector binary section,
|
||||
/// save address to put in section header
|
||||
///??? what if no data packets?
|
||||
///??? what if have exceptions while write, what is state of file? will
|
||||
/// close report file
|
||||
/// good/bad?
|
||||
// If first data packet written for this CompressedVector binary section,
|
||||
// save address to put in section header
|
||||
//??? what if no data packets?
|
||||
//??? what if have exceptions while write, what is state of file? will
|
||||
// close report file
|
||||
// good/bad?
|
||||
if ( dataPacketsCount_ == 0 )
|
||||
{
|
||||
dataPhysicalOffset_ = packetPhysicalOffset;
|
||||
}
|
||||
dataPacketsCount_++;
|
||||
|
||||
///!!! update seekIndex here? if started new chunk?
|
||||
// !!! update seekIndex here? if started new chunk?
|
||||
|
||||
/// Return physical offset of data packet for potential use in seekIndex
|
||||
// Return physical offset of data packet for potential use in seekIndex
|
||||
return ( packetPhysicalOffset ); //??? needed
|
||||
}
|
||||
|
||||
// If we don't have any records, write a packet which is only the header + zero padding.
|
||||
// Code is a simplified version of packetWrite().
|
||||
void CompressedVectorWriterImpl::packetWriteZeroRecords()
|
||||
{
|
||||
ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
|
||||
|
||||
dataPacket_.header.reset();
|
||||
|
||||
// Use temp buf in object (is 64KBytes long) instead of allocating each time here
|
||||
char *packet = reinterpret_cast<char *>( &dataPacket_ );
|
||||
|
||||
auto packetLength = static_cast<unsigned int>( sizeof( DataPacketHeader ) );
|
||||
|
||||
// packetLength must be multiple of 4, add zero padding
|
||||
auto data = reinterpret_cast<char *>( &packet[sizeof( DataPacketHeader )] );
|
||||
while ( packetLength % 4 )
|
||||
{
|
||||
*data++ = 0;
|
||||
|
||||
packetLength++;
|
||||
}
|
||||
|
||||
// Prepare header in dataPacket_, now that we are sure of packetLength
|
||||
dataPacket_.header.packetLogicalLengthMinus1 = static_cast<uint16_t>( packetLength - 1 );
|
||||
|
||||
// Double check that data packet is well formed
|
||||
dataPacket_.verify( packetLength );
|
||||
|
||||
// Write packet at beginning of free space in file
|
||||
uint64_t packetLogicalOffset = imf->allocateSpace( packetLength, false );
|
||||
uint64_t packetPhysicalOffset = imf->file_->logicalToPhysical( packetLogicalOffset );
|
||||
|
||||
imf->file_->seek( packetLogicalOffset );
|
||||
imf->file_->write( packet, packetLength );
|
||||
|
||||
// If first data packet written for this CompressedVector binary section,
|
||||
// save address to put in section header
|
||||
if ( dataPacketsCount_ == 0 )
|
||||
{
|
||||
dataPhysicalOffset_ = packetPhysicalOffset;
|
||||
}
|
||||
|
||||
dataPacketsCount_++;
|
||||
}
|
||||
|
||||
// Write one index packet.
|
||||
// We don't have an interface to work with index packets, but one is required by the standard, so
|
||||
// write one index packet with one entry pointing to the first data packet.
|
||||
void e57::CompressedVectorWriterImpl::packetWriteIndex()
|
||||
{
|
||||
ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
|
||||
|
||||
IndexPacket indexPacket;
|
||||
|
||||
indexPacket.entries[0].chunkPhysicalOffset = dataPhysicalOffset_;
|
||||
|
||||
const auto cPacketLength = sizeof( IndexPacketHeader ) + sizeof( IndexPacket::Entry );
|
||||
|
||||
indexPacket.header.packetLogicalLengthMinus1 = cPacketLength - 1;
|
||||
indexPacket.header.entryCount = 1;
|
||||
|
||||
uint64_t packetLogicalOffset = imf->allocateSpace( cPacketLength, false );
|
||||
topIndexPhysicalOffset_ = imf->file_->logicalToPhysical( packetLogicalOffset );
|
||||
|
||||
imf->file_->seek( packetLogicalOffset );
|
||||
imf->file_->write( reinterpret_cast<const char *>( &indexPacket ), cPacketLength );
|
||||
|
||||
indexPacketsCount_++;
|
||||
}
|
||||
|
||||
void CompressedVectorWriterImpl::flush()
|
||||
{
|
||||
for ( auto &bytestream : bytestreams_ )
|
||||
@@ -601,7 +700,9 @@ namespace e57
|
||||
const char *srcFunctionName ) const
|
||||
{
|
||||
// unimplemented...
|
||||
(void)srcFileName; (void)srcLineNumber; (void)srcFunctionName;
|
||||
E57_UNUSED( srcFileName );
|
||||
E57_UNUSED( srcLineNumber );
|
||||
E57_UNUSED( srcFunctionName );
|
||||
}
|
||||
|
||||
void CompressedVectorWriterImpl::checkWriterOpen( const char *srcFileName, int srcLineNumber,
|
||||
@@ -609,13 +710,14 @@ namespace e57
|
||||
{
|
||||
if ( !isOpen_ )
|
||||
{
|
||||
throw E57Exception( E57_ERROR_WRITER_NOT_OPEN,
|
||||
"imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName(),
|
||||
throw E57Exception( ErrorWriterNotOpen,
|
||||
"imageFileName=" + cVector_->imageFileName() +
|
||||
" cvPathName=" + cVector_->pathName(),
|
||||
srcFileName, srcLineNumber, srcFunctionName );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void CompressedVectorWriterImpl::dump( int indent, std::ostream &os )
|
||||
{
|
||||
os << space( indent ) << "isOpen:" << isOpen_ << std::endl;
|
||||
@@ -638,21 +740,24 @@ namespace e57
|
||||
bytestreams_.at( i )->dump( indent + 4, os );
|
||||
}
|
||||
|
||||
/// Don't call dump() for DataPacket, since it may contain junk when
|
||||
/// debugging. Just print a few byte values.
|
||||
// Don't call dump() for DataPacket, since it may contain junk when
|
||||
// debugging. Just print a few byte values.
|
||||
os << space( indent ) << "dataPacket:" << std::endl;
|
||||
auto p = reinterpret_cast<uint8_t *>( &dataPacket_ );
|
||||
|
||||
for ( unsigned i = 0; i < 40; ++i )
|
||||
{
|
||||
os << space( indent + 4 ) << "dataPacket[" << i << "]: " << static_cast<unsigned>( p[i] ) << std::endl;
|
||||
os << space( indent + 4 ) << "dataPacket[" << i << "]: " << static_cast<unsigned>( p[i] )
|
||||
<< std::endl;
|
||||
}
|
||||
os << space( indent + 4 ) << "more unprinted..." << std::endl;
|
||||
|
||||
os << space( indent ) << "sectionHeaderLogicalStart: " << sectionHeaderLogicalStart_ << std::endl;
|
||||
os << space( indent ) << "sectionHeaderLogicalStart: " << sectionHeaderLogicalStart_
|
||||
<< std::endl;
|
||||
os << space( indent ) << "sectionLogicalLength: " << sectionLogicalLength_ << std::endl;
|
||||
os << space( indent ) << "dataPhysicalOffset: " << dataPhysicalOffset_ << std::endl;
|
||||
os << space( indent ) << "topIndexPhysicalOffset: " << topIndexPhysicalOffset_ << std::endl;
|
||||
os << space( indent ) << "topIndexPhysicalOffset: " << topIndexPhysicalOffset_
|
||||
<< std::endl;
|
||||
os << space( indent ) << "recordCount: " << recordCount_ << std::endl;
|
||||
os << space( indent ) << "dataPacketsCount: " << dataPacketsCount_ << std::endl;
|
||||
os << space( indent ) << "indexPacketsCount: " << indexPacketsCount_ << std::endl;
|
||||
|
||||
@@ -34,28 +34,33 @@ namespace e57
|
||||
class CompressedVectorWriterImpl
|
||||
{
|
||||
public:
|
||||
CompressedVectorWriterImpl( std::shared_ptr<CompressedVectorNodeImpl> ni, std::vector<SourceDestBuffer> &sbufs );
|
||||
CompressedVectorWriterImpl( std::shared_ptr<CompressedVectorNodeImpl> ni,
|
||||
std::vector<SourceDestBuffer> &sbufs );
|
||||
~CompressedVectorWriterImpl();
|
||||
void write( const size_t requestedRecordCount );
|
||||
void write( std::vector<SourceDestBuffer> &sbufs, const size_t requestedRecordCount );
|
||||
|
||||
void write( size_t requestedRecordCount );
|
||||
void write( std::vector<SourceDestBuffer> &sbufs, size_t requestedRecordCount );
|
||||
bool isOpen() const;
|
||||
std::shared_ptr<CompressedVectorNodeImpl> compressedVectorNode() const;
|
||||
void close();
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout );
|
||||
#endif
|
||||
|
||||
private:
|
||||
void checkImageFileOpen( const char *srcFileName, int srcLineNumber, const char *srcFunctionName ) const;
|
||||
void checkWriterOpen( const char *srcFileName, int srcLineNumber, const char *srcFunctionName ) const;
|
||||
void checkImageFileOpen( const char *srcFileName, int srcLineNumber,
|
||||
const char *srcFunctionName ) const;
|
||||
void checkWriterOpen( const char *srcFileName, int srcLineNumber,
|
||||
const char *srcFunctionName ) const;
|
||||
void setBuffers( std::vector<SourceDestBuffer> &sbufs ); //???needed?
|
||||
size_t totalOutputAvailable() const;
|
||||
size_t currentPacketSize() const;
|
||||
uint64_t packetWrite();
|
||||
void flush();
|
||||
void packetWriteZeroRecords();
|
||||
void packetWriteIndex();
|
||||
|
||||
//??? no default ctor, copy, assignment?
|
||||
void flush();
|
||||
|
||||
std::vector<SourceDestBuffer> sbufs_;
|
||||
std::shared_ptr<CompressedVectorNodeImpl> cVector_;
|
||||
|
||||
25
src/3rdParty/libE57Format/src/DecodeChannel.cpp
vendored
25
src/3rdParty/libE57Format/src/DecodeChannel.cpp
vendored
@@ -27,13 +27,13 @@
|
||||
|
||||
#include "DecodeChannel.h"
|
||||
#include "SourceDestBufferImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
DecodeChannel::DecodeChannel( SourceDestBuffer dbuf_arg, std::shared_ptr<Decoder> decoder_arg,
|
||||
unsigned bytestreamNumber_arg, uint64_t maxRecordCount_arg ) :
|
||||
dbuf( dbuf_arg ),
|
||||
decoder( decoder_arg ), bytestreamNumber( bytestreamNumber_arg )
|
||||
dbuf( dbuf_arg ), decoder( decoder_arg ), bytestreamNumber( bytestreamNumber_arg )
|
||||
{
|
||||
maxRecordCount = maxRecordCount_arg;
|
||||
currentPacketLogicalOffset = 0;
|
||||
@@ -44,30 +44,30 @@ namespace e57
|
||||
|
||||
bool DecodeChannel::isOutputBlocked() const
|
||||
{
|
||||
/// If we have completed the entire vector, we are done
|
||||
// If we have completed the entire vector, we are done
|
||||
if ( decoder->totalRecordsCompleted() >= maxRecordCount )
|
||||
{
|
||||
return ( true );
|
||||
}
|
||||
|
||||
/// If we have filled the dest buffer, we are blocked
|
||||
// If we have filled the dest buffer, we are blocked
|
||||
return ( dbuf.impl()->nextIndex() == dbuf.impl()->capacity() );
|
||||
}
|
||||
|
||||
bool DecodeChannel::isInputBlocked() const
|
||||
{
|
||||
/// If have read until the section end, we are done
|
||||
// If have read until the section end, we are done
|
||||
if ( inputFinished )
|
||||
{
|
||||
return ( true );
|
||||
}
|
||||
|
||||
/// If have eaten all the input in the current packet, we are blocked.
|
||||
// If have eaten all the input in the current packet, we are blocked.
|
||||
return ( currentBytestreamBufferIndex == currentBytestreamBufferLength );
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
void DecodeChannel::dump( int indent, std::ostream &os )
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void DecodeChannel::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
os << space( indent ) << "dbuf" << std::endl;
|
||||
dbuf.dump( indent + 4, os );
|
||||
@@ -77,9 +77,12 @@ namespace e57
|
||||
|
||||
os << space( indent ) << "bytestreamNumber: " << bytestreamNumber << std::endl;
|
||||
os << space( indent ) << "maxRecordCount: " << maxRecordCount << std::endl;
|
||||
os << space( indent ) << "currentPacketLogicalOffset: " << currentPacketLogicalOffset << std::endl;
|
||||
os << space( indent ) << "currentBytestreamBufferIndex: " << currentBytestreamBufferIndex << std::endl;
|
||||
os << space( indent ) << "currentBytestreamBufferLength: " << currentBytestreamBufferLength << std::endl;
|
||||
os << space( indent ) << "currentPacketLogicalOffset: " << currentPacketLogicalOffset
|
||||
<< std::endl;
|
||||
os << space( indent ) << "currentBytestreamBufferIndex: " << currentBytestreamBufferIndex
|
||||
<< std::endl;
|
||||
os << space( indent ) << "currentBytestreamBufferLength: " << currentBytestreamBufferLength
|
||||
<< std::endl;
|
||||
os << space( indent ) << "inputFinished: " << inputFinished << std::endl;
|
||||
os << space( indent ) << "isInputBlocked(): " << isInputBlocked() << std::endl;
|
||||
os << space( indent ) << "isOutputBlocked(): " << isOutputBlocked() << std::endl;
|
||||
|
||||
11
src/3rdParty/libE57Format/src/DecodeChannel.h
vendored
11
src/3rdParty/libE57Format/src/DecodeChannel.h
vendored
@@ -34,7 +34,7 @@ namespace e57
|
||||
|
||||
struct DecodeChannel
|
||||
{
|
||||
SourceDestBuffer dbuf; //??? for now, one input per channel
|
||||
SourceDestBuffer dbuf;
|
||||
std::shared_ptr<Decoder> decoder;
|
||||
unsigned bytestreamNumber;
|
||||
uint64_t maxRecordCount;
|
||||
@@ -43,13 +43,14 @@ namespace e57
|
||||
size_t currentBytestreamBufferLength;
|
||||
bool inputFinished;
|
||||
|
||||
DecodeChannel( SourceDestBuffer dbuf_arg, std::shared_ptr<Decoder> decoder_arg, unsigned bytestreamNumber_arg,
|
||||
uint64_t maxRecordCount_arg );
|
||||
DecodeChannel( SourceDestBuffer dbuf_arg, std::shared_ptr<Decoder> decoder_arg,
|
||||
unsigned bytestreamNumber_arg, uint64_t maxRecordCount_arg );
|
||||
|
||||
bool isOutputBlocked() const;
|
||||
bool isInputBlocked() const; /// has exhausted data in the current packet
|
||||
#ifdef E57_DEBUG
|
||||
void dump( int indent = 0, std::ostream &os = std::cout );
|
||||
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
553
src/3rdParty/libE57Format/src/Decoder.cpp
vendored
553
src/3rdParty/libE57Format/src/Decoder.cpp
vendored
File diff suppressed because it is too large
Load Diff
61
src/3rdParty/libE57Format/src/Decoder.h
vendored
61
src/3rdParty/libE57Format/src/Decoder.h
vendored
@@ -36,24 +36,27 @@ namespace e57
|
||||
public:
|
||||
static std::shared_ptr<Decoder> DecoderFactory( unsigned bytestreamNumber,
|
||||
const CompressedVectorNodeImpl *cVector,
|
||||
std::vector<SourceDestBuffer> &dbufs, const ustring &codecPath );
|
||||
std::vector<SourceDestBuffer> &dbufs,
|
||||
const ustring &codecPath );
|
||||
Decoder() = delete;
|
||||
virtual ~Decoder() = default;
|
||||
|
||||
virtual void destBufferSetNew( std::vector<SourceDestBuffer> &dbufs ) = 0;
|
||||
virtual uint64_t totalRecordsCompleted() = 0;
|
||||
virtual size_t inputProcess( const char *source, const size_t count ) = 0;
|
||||
virtual size_t inputProcess( const char *source, size_t count ) = 0;
|
||||
virtual void stateReset() = 0;
|
||||
|
||||
unsigned bytestreamNumber() const
|
||||
{
|
||||
return bytestreamNumber_;
|
||||
}
|
||||
#ifdef E57_DEBUG
|
||||
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
virtual void dump( int indent = 0, std::ostream &os = std::cout ) = 0;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Decoder( unsigned bytestreamNumber );
|
||||
explicit Decoder( unsigned bytestreamNumber );
|
||||
|
||||
unsigned int bytestreamNumber_;
|
||||
};
|
||||
@@ -68,14 +71,15 @@ namespace e57
|
||||
return ( currentRecordIndex_ );
|
||||
}
|
||||
|
||||
size_t inputProcess( const char *source, const size_t availableByteCount ) override;
|
||||
virtual size_t inputProcessAligned( const char *inbuf, const size_t firstBit, const size_t endBit ) = 0;
|
||||
size_t inputProcess( const char *source, size_t availableByteCount ) override;
|
||||
virtual size_t inputProcessAligned( const char *inbuf, size_t firstBit, size_t endBit ) = 0;
|
||||
|
||||
void stateReset() override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
BitpackDecoder( unsigned bytestreamNumber, SourceDestBuffer &dbuf, unsigned alignmentSize,
|
||||
uint64_t maxRecordCount );
|
||||
@@ -98,28 +102,31 @@ namespace e57
|
||||
class BitpackFloatDecoder : public BitpackDecoder
|
||||
{
|
||||
public:
|
||||
BitpackFloatDecoder( unsigned bytestreamNumber, SourceDestBuffer &dbuf, FloatPrecision precision,
|
||||
uint64_t maxRecordCount );
|
||||
BitpackFloatDecoder( unsigned bytestreamNumber, SourceDestBuffer &dbuf,
|
||||
FloatPrecision precision, uint64_t maxRecordCount );
|
||||
|
||||
size_t inputProcessAligned( const char *inbuf, const size_t firstBit, const size_t endBit ) override;
|
||||
size_t inputProcessAligned( const char *inbuf, size_t firstBit, size_t endBit ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
FloatPrecision precision_ = E57_SINGLE;
|
||||
FloatPrecision precision_ = PrecisionSingle;
|
||||
};
|
||||
|
||||
class BitpackStringDecoder : public BitpackDecoder
|
||||
{
|
||||
public:
|
||||
BitpackStringDecoder( unsigned bytestreamNumber, SourceDestBuffer &dbuf, uint64_t maxRecordCount );
|
||||
BitpackStringDecoder( unsigned bytestreamNumber, SourceDestBuffer &dbuf,
|
||||
uint64_t maxRecordCount );
|
||||
|
||||
size_t inputProcessAligned( const char *inbuf, const size_t firstBit, const size_t endBit ) override;
|
||||
size_t inputProcessAligned( const char *inbuf, size_t firstBit, size_t endBit ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool readingPrefix_ = true;
|
||||
int prefixLength_ = 1;
|
||||
@@ -133,14 +140,16 @@ namespace e57
|
||||
template <typename RegisterT> class BitpackIntegerDecoder : public BitpackDecoder
|
||||
{
|
||||
public:
|
||||
BitpackIntegerDecoder( bool isScaledInteger, unsigned bytestreamNumber, SourceDestBuffer &dbuf, int64_t minimum,
|
||||
int64_t maximum, double scale, double offset, uint64_t maxRecordCount );
|
||||
BitpackIntegerDecoder( bool isScaledInteger, unsigned bytestreamNumber,
|
||||
SourceDestBuffer &dbuf, int64_t minimum, int64_t maximum, double scale,
|
||||
double offset, uint64_t maxRecordCount );
|
||||
|
||||
size_t inputProcessAligned( const char *inbuf, const size_t firstBit, const size_t endBit ) override;
|
||||
size_t inputProcessAligned( const char *inbuf, size_t firstBit, size_t endBit ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool isScaledInteger_;
|
||||
int64_t minimum_;
|
||||
@@ -149,23 +158,29 @@ namespace e57
|
||||
double offset_;
|
||||
unsigned bitsPerRecord_;
|
||||
RegisterT destBitMask_;
|
||||
static constexpr size_t RegisterBits = sizeof( RegisterT ) * 8;
|
||||
};
|
||||
|
||||
class ConstantIntegerDecoder : public Decoder
|
||||
{
|
||||
public:
|
||||
ConstantIntegerDecoder( bool isScaledInteger, unsigned bytestreamNumber, SourceDestBuffer &dbuf, int64_t minimum,
|
||||
double scale, double offset, uint64_t maxRecordCount );
|
||||
ConstantIntegerDecoder( bool isScaledInteger, unsigned bytestreamNumber,
|
||||
SourceDestBuffer &dbuf, int64_t minimum, double scale, double offset,
|
||||
uint64_t maxRecordCount );
|
||||
void destBufferSetNew( std::vector<SourceDestBuffer> &dbufs ) override;
|
||||
|
||||
uint64_t totalRecordsCompleted() override
|
||||
{
|
||||
return currentRecordIndex_;
|
||||
}
|
||||
size_t inputProcess( const char *source, const size_t availableByteCount ) override;
|
||||
|
||||
size_t inputProcess( const char *source, size_t availableByteCount ) override;
|
||||
void stateReset() override;
|
||||
#ifdef E57_DEBUG
|
||||
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
uint64_t currentRecordIndex_ = 0;
|
||||
uint64_t maxRecordCount_;
|
||||
|
||||
650
src/3rdParty/libE57Format/src/E57Exception.cpp
vendored
650
src/3rdParty/libE57Format/src/E57Exception.cpp
vendored
@@ -26,422 +26,344 @@
|
||||
*/
|
||||
|
||||
#include "E57Exception.h"
|
||||
#include "E57Version.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
/*!
|
||||
@class E57Exception
|
||||
@brief Object thrown by E57 API functions to communicate the conditions of an
|
||||
error.
|
||||
|
||||
@brief Object thrown by E57 API functions to communicate the conditions of an error.
|
||||
|
||||
@details
|
||||
The E57Exception object communicates information about errors occurring in calls
|
||||
to the E57 API functions. The error information is communicated from the
|
||||
location in the E57 implementation where the error was detected to the @c catch
|
||||
statement in the code of the API user. The state of E57Exception object has one
|
||||
mandatory field, the errorCode, and several optional fields that can be set
|
||||
depending on the debug level of the E57 implementation. There are three optional
|
||||
fields that encode the location in the source code of the E57 implementation
|
||||
where the error was detected: @c sourceFileName, @c sourceFunctionName, and @c
|
||||
sourceLineNumber. Another optional field is the @c context string that is human
|
||||
(or at least programmer) readable, which can capture some variable values that
|
||||
might be useful in debugging. The E57Exception class is derived from
|
||||
std::exception. So applications that only catch std::exceptions will detect
|
||||
E57Exceptions (but with no information about the origin of the error).
|
||||
The E57Exception object communicates information about errors occurring in calls to the E57 API
|
||||
functions. The error information is communicated from the location in the E57 implementation
|
||||
where the error was detected to the @c catch statement in the code of the API user. The state of
|
||||
E57Exception object has one mandatory field, the errorCode, and several optional fields that can
|
||||
be set depending on the debug level of the E57 implementation. There are three optional fields
|
||||
that encode the location in the source code of the E57 implementation where the error was
|
||||
detected: @c sourceFileName, @c sourceFunctionName, and @c sourceLineNumber. Another optional
|
||||
field is the @c context string that is human (or at least programmer) readable, which can capture
|
||||
some variable values that might be useful in debugging. The E57Exception class is derived from
|
||||
std::exception. So applications that only catch std::exceptions will detect E57Exceptions (but
|
||||
with no information about the origin of the error).
|
||||
|
||||
Many other APIs use error codes (defined integer constants) returned from the
|
||||
API functions to communicate success or failure of the requested command. In
|
||||
contrast, the E57 API uses the C++ exception mechanism to communicate failure
|
||||
(success is communicated by the return of the function without exception).
|
||||
E57Exception(E57_SUCCESS) is never thrown. The API ErrorCode is packaged inside
|
||||
the E57Exception. The documentation for each function in the API declares which
|
||||
ErrorCode values (inside an E57Exception) can possibly be thrown by the
|
||||
function. Some API functions do not throw any E57Exceptions, and this is
|
||||
documented by the designation "No E57Exceptions." in the "Exceptions:" section
|
||||
of the function documentation page.
|
||||
Many other APIs use error codes (defined integer constants) returned from the API functions to
|
||||
communicate success or failure of the requested command. In contrast, the E57 API uses the C++
|
||||
exception mechanism to communicate failure (success is communicated by the return of the function
|
||||
without exception). ::Success is never thrown. The API ErrorCode is packaged inside the
|
||||
E57Exception. The documentation for each function in the API declares which ErrorCode values
|
||||
(inside an E57Exception) can possibly be thrown by the function. Some API functions do not throw
|
||||
any E57Exceptions, and this is documented by the designation "No E57Exceptions." in the
|
||||
"Exceptions:" section of the function documentation page.
|
||||
|
||||
If an API function does throw an E57Exception, the API user will rightfully be
|
||||
concerned about the state of all of the API objects. There are four categories
|
||||
of guarantee about the state of all objects that the API specifies.
|
||||
If an API function does throw an E57Exception, the API user will rightfully be concerned about
|
||||
the state of all of the API objects. There are four categories of guarantee about the state of
|
||||
all objects that the API specifies.
|
||||
|
||||
1) <b>All objects unchanged</b> - all API objects are left in their original
|
||||
state before the API function was called. This is the default guarantee, so if
|
||||
there is no notation next to the ErrorCode in the "Exceptions:" section of the
|
||||
function documentation page, the this category is implied.
|
||||
1) <b>All objects unchanged</b> - all API objects are left in their original state before the API
|
||||
function was called. This is the default guarantee, so if there is no notation next to the
|
||||
ErrorCode in the "Exceptions:" section of the function documentation page, the this category is
|
||||
implied.
|
||||
|
||||
2) <b>XXX object modified, but consistent</b> - The given object (or objects)
|
||||
have been modified, but are left in a consistent state.
|
||||
2) <b>XXX object modified, but consistent</b> - The given object (or objects) have been modified,
|
||||
but are left in a consistent state.
|
||||
|
||||
3) <b>XXX object in undocumented state</b> - The given object (or objects) may
|
||||
have been left in an inconsistent state, and the only safe thing to do with them
|
||||
is to call their destructor.
|
||||
3) <b>XXX object in undocumented state</b> - The given object (or objects) may have been left in
|
||||
an inconsistent state, and the only safe thing to do with them is to call their destructor.
|
||||
|
||||
4) <b>All objects in undocumented state</b> - A very serious consistency error
|
||||
has been detected, and the state of all API objects is suspect. The only safe
|
||||
thing to do is to call their destructors.
|
||||
4) <b>All objects in undocumented state</b> - A very serious consistency error has been detected,
|
||||
and the state of all API objects is suspect. The only safe thing to do is to call their
|
||||
destructors.
|
||||
|
||||
Almost all of the API functions can throw the following two ErrorCodes:
|
||||
E57_ERROR_IMAGEFILE_NOT_OPEN and E57_ERROR_INTERNAL. In some E57
|
||||
implementations, the tree information may be stored on disk rather than in
|
||||
memory. If the disk file is closed, even the most basic information may not be
|
||||
available about nodes in the tree. So if the ImageFile is closed (by calling
|
||||
ImageFile::close), the API user must be ready for many of the API functions to
|
||||
throw E57Exception(E57_ERROR_IMAGEFILE_NOT_OPEN). Secondly, regarding the
|
||||
E57_ERROR_INTERNAL error, there is a lot of consistency checking in the
|
||||
Reference Implementation, and there may be much more added. Even if some API
|
||||
routines do not now throw E57_ERROR_INTERNAL, they could some time in the
|
||||
future, or in different implementations. So the right to throw
|
||||
E57_ERROR_INTERNAL is reserved for every API function (except those that by
|
||||
Almost all of the API functions can throw the following two ErrorCodes: ::ErrorImageFileNotOpen
|
||||
and ::ErrorInternal. In some E57 implementations, the tree information may be stored on disk
|
||||
rather than in memory. If the disk file is closed, even the most basic information may not be
|
||||
available about nodes in the tree. So if the ImageFile is closed (by calling ImageFile::close),
|
||||
the API user must be ready for many of the API functions to throw ::ErrorImageFileNotOpen.
|
||||
Secondly, regarding the ErrorInternal error, there is a lot of consistency checking in the
|
||||
Reference Implementation, and there may be much more added. Even if some API routines do not now
|
||||
throw ::ErrorInternal, they could some time in the future, or in different implementations. So
|
||||
the right to throw ::ErrorInternal is reserved for every API function (except those that by
|
||||
design can't throw E57Exceptions).
|
||||
|
||||
It is strongly recommended that catch statements in user code that call API
|
||||
functions catch E57Exception by reference (i.e. <tt>catch (E57Exception&
|
||||
ex)</tt> and, if necessary, rethrow using the syntax that throws the currently
|
||||
active exception (i.e. <tt>throw;</tt>).
|
||||
It is strongly recommended that catch statements in user code that call API functions catch
|
||||
E57Exception by reference (i.e. <tt>catch (E57Exception& ex)</tt> and, if necessary, rethrow
|
||||
using the syntax that throws the currently active exception (i.e. <tt>throw;</tt>).
|
||||
|
||||
Exceptions other that E57Exception may be thrown by calls to API functions (e.g.
|
||||
std::bad_alloc). Production code will likely have catch handlers for these
|
||||
exceptions as well.
|
||||
|
||||
@see HelloWorld.cpp example
|
||||
Exceptions other that E57Exception may be thrown by calls to API functions (e.g. std::bad_alloc).
|
||||
Production code will likely have catch handlers for these exceptions as well.
|
||||
*/
|
||||
|
||||
//! @cond documentNonPublic The following isn't part of the API, and isn't
|
||||
//! documented.
|
||||
E57Exception::E57Exception( ErrorCode ecode, const std::string &context, const std::string &srcFileName,
|
||||
int srcLineNumber, const char *srcFunctionName ) :
|
||||
errorCode_( ecode ),
|
||||
context_( context ), sourceFunctionName_( srcFunctionName ), sourceLineNumber_( srcLineNumber )
|
||||
{
|
||||
sourceFileName_ = srcFileName.substr( srcFileName.find_last_of( "/\\" ) + 1 );
|
||||
}
|
||||
//! @endcond
|
||||
|
||||
/*!
|
||||
@brief Print error information on a given output stream.
|
||||
@param [in] reportingFileName Name of file where catch statement caught
|
||||
the exception. NULL if unknown.
|
||||
@param [in] reportingLineNumber Number of source code line where catch
|
||||
statement caught the exception. 0 if unknown.
|
||||
@param [in] reportingFunctionName String name of function containing catch
|
||||
statement that caught the exception. NULL if unknown.
|
||||
@param [in] os Output string to print a summary of exception information and
|
||||
location of catch statement.
|
||||
@details
|
||||
The amount of information printed to output stream may depend on whether the E57
|
||||
implementation was built with debugging enabled.
|
||||
@post No visible state is modified.
|
||||
@throw No E57Exceptions.
|
||||
@see E57ExceptionFunctions.cpp example, ErrorCode, HelloWorld.cpp example
|
||||
*/
|
||||
void E57Exception::report( const char *reportingFileName, int reportingLineNumber, const char *reportingFunctionName,
|
||||
std::ostream &os ) const
|
||||
{
|
||||
os << "**** Got an e57 exception: " << e57::Utilities::errorCodeToString( errorCode() ) << std::endl;
|
||||
@fn const char *E57Exception::what()
|
||||
@brief Get string description of exception category.
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
os << " Debug info: " << std::endl;
|
||||
os << " context: " << context_ << std::endl;
|
||||
os << " sourceFunctionName: " << sourceFunctionName_ << std::endl;
|
||||
if ( reportingFunctionName )
|
||||
os << " reportingFunctionName: " << reportingFunctionName << std::endl;
|
||||
|
||||
/*** Add a line in error message that a smart editor (gnu emacs) can
|
||||
* interpret as a link to the source code: */
|
||||
os << sourceFileName_ << "(" << sourceLineNumber_ << ") : error C" << errorCode_ << ": <--- occurred on"
|
||||
<< std::endl;
|
||||
if ( reportingFileName )
|
||||
os << reportingFileName << "(" << reportingLineNumber << ") : error C0: <--- reported on" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get numeric ::ErrorCode associated with the exception.
|
||||
@post No visible state is modified.
|
||||
@return The numeric ::ErrorCode associated with the exception.
|
||||
@throw No E57Exceptions.
|
||||
@see E57ExceptionFunctions.cpp example, E57Utilities::errorCodeToString,
|
||||
ErrorCode
|
||||
*/
|
||||
ErrorCode E57Exception::errorCode() const
|
||||
{
|
||||
return errorCode_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get human-readable string that describes the context of the error.
|
||||
@details
|
||||
The context string may include values in object state, or function arguments.
|
||||
The format of the context string is not standardized.
|
||||
However, in the Reference Implementation, many strings contain a sequence of "
|
||||
VARNAME=VARVALUE" fields.
|
||||
@post No visible state is modified.
|
||||
@return The human-readable string that describes the context of the error.
|
||||
@throw No E57Exceptions.
|
||||
@see E57ExceptionsFunctions.cpp example
|
||||
*/
|
||||
std::string E57Exception::context() const
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get string description of exception category.
|
||||
@details
|
||||
Returns "E57 Exception" for all E57Exceptions, no matter what the errorCode.
|
||||
@post No visible state is modified.
|
||||
@return The string description of exception category.
|
||||
@throw No E57Exceptions.
|
||||
@see E57ExceptionsFunctions.cpp example
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The string description of exception category.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
*/
|
||||
const char *E57Exception::what() const noexcept
|
||||
{
|
||||
return "E57 exception";
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get name of source file where exception occurred, for debugging.
|
||||
@fn void E57Exception::report( const char *reportingFileName, int reportingLineNumber,
|
||||
const char *reportingFunctionName, std::ostream &os )
|
||||
@brief Print error information on a given output stream.
|
||||
|
||||
@param [in] reportingFileName Name of file where catch statement caught the exception. NULL if
|
||||
unknown.
|
||||
@param [in] reportingLineNumber Number of source code line where catch statement caught the
|
||||
exception. 0 if unknown.
|
||||
@param [in] reportingFunctionName String name of function containing catch statement that caught
|
||||
the exception. NULL if unknown.
|
||||
@param [in] os Output string to print a summary of exception information and location of catch
|
||||
statement.
|
||||
|
||||
@details
|
||||
May return the value of the macro variable __FILE__ at the location where the
|
||||
E57Exception was constructed. May return the empty string ("") in some E57
|
||||
implementations.
|
||||
@post No visible state is modified.
|
||||
@return The name of source file where exception occurred, for debugging.
|
||||
@throw No E57Exceptions.
|
||||
@see E57ExceptionsFunctions.cpp example
|
||||
The amount of information printed to output stream may depend on whether the E57 implementation
|
||||
was built with debugging enabled.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see ErrorCode
|
||||
*/
|
||||
const char *E57Exception::sourceFileName() const
|
||||
{
|
||||
return sourceFileName_.c_str();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get name of function in source code where the error occurred , for
|
||||
debugging.
|
||||
@details
|
||||
May return the value of the macro variable __FUNCTION__ at the location where
|
||||
the E57Exception was constructed. May return the empty string ("") in some E57
|
||||
implementations.
|
||||
@post No visible state is modified.
|
||||
@return The name of source code function where the error occurred , for
|
||||
debugging.
|
||||
@throw No E57Exceptions.
|
||||
@fn ErrorCode E57Exception::errorCode()
|
||||
@brief Get numeric ::ErrorCode associated with the exception.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The numeric ::ErrorCode associated with the exception.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see E57Exception::errorStr, Utilities::errorCodeToString, ErrorCode
|
||||
*/
|
||||
const char *E57Exception::sourceFunctionName() const
|
||||
{
|
||||
return sourceFunctionName_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get line number in source code file where exception occurred, for
|
||||
debugging.
|
||||
@details
|
||||
May return the value of the macro variable __LINE__ at the location where the
|
||||
E57Exception was constructed. May return the empty string ("") in some E57
|
||||
implementations.
|
||||
@post No visible state is modified.
|
||||
@return The line number in source code file where exception occurred, for
|
||||
debugging.
|
||||
@throw No E57Exceptions.
|
||||
@fn std::string E57Exception::errorStr()
|
||||
@brief Get error string associated with the exception.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The error string associated with the exception.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
*/
|
||||
|
||||
/*!
|
||||
@fn std::string E57Exception::context()
|
||||
@brief Get human-readable string that describes the context of the error.
|
||||
|
||||
@details
|
||||
The context string may include values in object state, or function arguments. The format of the
|
||||
context string is not standardized. However, in the Reference Implementation, many strings
|
||||
contain a sequence of " VARNAME=VARVALUE" fields.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The human-readable string that describes the context of the error.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
*/
|
||||
|
||||
/*!
|
||||
@fn const char *E57Exception::sourceFileName()
|
||||
@brief Get name of source file where exception occurred, for debugging.
|
||||
|
||||
@details
|
||||
May return the value of the macro variable __FILE__ at the location where the E57Exception was
|
||||
constructed. May return the empty string ("") in some E57 implementations.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The name of source file where exception occurred, for debugging.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
*/
|
||||
|
||||
/*!
|
||||
@fn const char *E57Exception::sourceFunctionName()
|
||||
@brief Get name of function in source code where the error occurred , for
|
||||
debugging.
|
||||
|
||||
@details
|
||||
May return the value of the macro variable __FUNCTION__ at the location where the E57Exception
|
||||
was constructed. May return the empty string ("") in some E57 implementations.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The name of source code function where the error occurred , for debugging.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
*/
|
||||
|
||||
/*!
|
||||
@fn int E57Exception::sourceLineNumber()
|
||||
@brief Get line number in source code file where exception occurred, for debugging.
|
||||
|
||||
@details
|
||||
May return the value of the macro variable __LINE__ at the location where the E57Exception was
|
||||
constructed. May return the empty string ("") in some E57 implementations.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The line number in source code file where exception occurred, for debugging.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
*/
|
||||
int E57Exception::sourceLineNumber() const
|
||||
{
|
||||
return sourceLineNumber_;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
|
||||
/*!
|
||||
@brief Get the version of ASTM E57 standard that the API implementation
|
||||
supports, and library id string.
|
||||
@param [out] astmMajor The major version number of the ASTM E57 standard
|
||||
supported.
|
||||
@param [out] astmMinor The minor version number of the ASTM E57 standard
|
||||
supported.
|
||||
@param [out] libraryId A string identifying the implementation of the API.
|
||||
@details
|
||||
Since the E57 implementation may be dynamically linked underneath the API, the
|
||||
version string for the implementation and the ASTM version that it supports
|
||||
can't be determined at compile-time. This function returns these identifiers
|
||||
from the underlying implementation.
|
||||
@throw No E57Exceptions.
|
||||
*/
|
||||
void Utilities::getVersions( int &astmMajor, int &astmMinor, std::string &libraryId )
|
||||
{
|
||||
/// REVISION_ID should be passed from compiler command line
|
||||
@brief Get short string description of an E57 ErrorCode.
|
||||
|
||||
#ifndef REVISION_ID
|
||||
#error "Need to specify REVISION_ID on command line"
|
||||
#endif
|
||||
@param [in] ecode The numeric errorCode from an E57Exception.
|
||||
|
||||
astmMajor = E57_FORMAT_MAJOR;
|
||||
astmMinor = E57_FORMAT_MINOR;
|
||||
libraryId = REVISION_ID;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get short string description of an E57 ErrorCode.
|
||||
@param [in] ecode The numeric errorCode from an E57Exception.
|
||||
@details
|
||||
The errorCode is translated into a one-line English string.
|
||||
@return English std::string describing error.
|
||||
@throw No E57Exceptions.
|
||||
@see E57Exception::errorCode
|
||||
|
||||
@return English std::string describing error.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see E57Exception::errorCode
|
||||
*/
|
||||
std::string Utilities::errorCodeToString( ErrorCode ecode )
|
||||
std::string Utilities::errorCodeToString( ErrorCode ecode ) noexcept
|
||||
{
|
||||
switch ( ecode )
|
||||
{
|
||||
// N.B. *** When changing error strings here, remember to update the
|
||||
// Doxygen strings in E57Exception.h ****
|
||||
case E57_SUCCESS:
|
||||
return "operation was successful (E57_SUCCESS)";
|
||||
case E57_ERROR_BAD_CV_HEADER:
|
||||
return "a CompressedVector binary header was bad "
|
||||
"(E57_ERROR_BAD_CV_HEADER)";
|
||||
case E57_ERROR_BAD_CV_PACKET:
|
||||
return "a CompressedVector binary packet was bad "
|
||||
"(E57_ERROR_BAD_CV_PACKET)";
|
||||
case E57_ERROR_CHILD_INDEX_OUT_OF_BOUNDS:
|
||||
case Success:
|
||||
return "operation was successful (Success)";
|
||||
case ErrorBadCVHeader:
|
||||
return "a CompressedVector binary header was bad (ErrorBadCVHeader)";
|
||||
case ErrorBadCVPacket:
|
||||
return "a CompressedVector binary packet was bad (ErrorBadCVPacket)";
|
||||
case ErrorChildIndexOutOfBounds:
|
||||
return "a numerical index identifying a child was out of bounds "
|
||||
"(E57_ERROR_CHILD_INDEX_OUT_OF_BOUNDS)";
|
||||
case E57_ERROR_SET_TWICE:
|
||||
return "attempted to set an existing child element to a new value "
|
||||
"(E57_ERROR_SET_TWICE)";
|
||||
case E57_ERROR_HOMOGENEOUS_VIOLATION:
|
||||
return "attempted to add an E57 Element that would have made the "
|
||||
"children of a "
|
||||
"homogeneous Vector have different types "
|
||||
"(E57_ERROR_HOMOGENEOUS_VIOLATION)";
|
||||
case E57_ERROR_VALUE_NOT_REPRESENTABLE:
|
||||
"(ErrorChildIndexOutOfBounds)";
|
||||
case ErrorSetTwice:
|
||||
return "attempted to set an existing child element to a new value (ErrorSetTwice)";
|
||||
case ErrorHomogeneousViolation:
|
||||
return "attempted to add an E57 Element that would have made the children of a "
|
||||
"homogeneous Vector have "
|
||||
"different types (E57_ERROR_HOMOGENEOUS_VIOLATION)";
|
||||
case ErrorValueNotRepresentable:
|
||||
return "a value could not be represented in the requested type "
|
||||
"(E57_ERROR_VALUE_NOT_REPRESENTABLE)";
|
||||
case E57_ERROR_SCALED_VALUE_NOT_REPRESENTABLE:
|
||||
return "after scaling the result could not be represented in the "
|
||||
"requested type "
|
||||
"(E57_ERROR_SCALED_VALUE_NOT_REPRESENTABLE)";
|
||||
case E57_ERROR_REAL64_TOO_LARGE:
|
||||
return "a 64 bit IEEE float was too large to store in a 32 bit IEEE "
|
||||
"float "
|
||||
"(E57_ERROR_REAL64_TOO_LARGE)";
|
||||
case E57_ERROR_EXPECTING_NUMERIC:
|
||||
return "Expecting numeric representation in user's buffer, found "
|
||||
"ustring "
|
||||
"(E57_ERROR_EXPECTING_NUMERIC)";
|
||||
case E57_ERROR_EXPECTING_USTRING:
|
||||
return "Expecting string representation in user's buffer, found "
|
||||
"numeric "
|
||||
"(E57_ERROR_EXPECTING_USTRING)";
|
||||
case E57_ERROR_INTERNAL:
|
||||
return "An unrecoverable inconsistent internal state was detected "
|
||||
"(E57_ERROR_INTERNAL)";
|
||||
case E57_ERROR_BAD_XML_FORMAT:
|
||||
return "E57 primitive not encoded in XML correctly "
|
||||
"(E57_ERROR_BAD_XML_FORMAT)";
|
||||
case E57_ERROR_XML_PARSER:
|
||||
return "XML not well formed (E57_ERROR_XML_PARSER)";
|
||||
case E57_ERROR_BAD_API_ARGUMENT:
|
||||
return "bad API function argument provided by user "
|
||||
"(E57_ERROR_BAD_API_ARGUMENT)";
|
||||
case E57_ERROR_FILE_IS_READ_ONLY:
|
||||
return "can't modify read only file (E57_ERROR_FILE_IS_READ_ONLY)";
|
||||
case E57_ERROR_BAD_CHECKSUM:
|
||||
return "checksum mismatch, file is corrupted (E57_ERROR_BAD_CHECKSUM)";
|
||||
case E57_ERROR_OPEN_FAILED:
|
||||
return "open() failed (E57_ERROR_OPEN_FAILED)";
|
||||
case E57_ERROR_CLOSE_FAILED:
|
||||
return "close() failed (E57_ERROR_CLOSE_FAILED)";
|
||||
case E57_ERROR_READ_FAILED:
|
||||
return "read() failed (E57_ERROR_READ_FAILED)";
|
||||
case E57_ERROR_WRITE_FAILED:
|
||||
return "write() failed (E57_ERROR_WRITE_FAILED)";
|
||||
case E57_ERROR_LSEEK_FAILED:
|
||||
return "lseek() failed (E57_ERROR_LSEEK_FAILED)";
|
||||
case E57_ERROR_PATH_UNDEFINED:
|
||||
return "E57 element path well formed but not defined "
|
||||
"(E57_ERROR_PATH_UNDEFINED)";
|
||||
case E57_ERROR_BAD_BUFFER:
|
||||
return "bad SourceDestBuffer (E57_ERROR_BAD_BUFFER)";
|
||||
case E57_ERROR_NO_BUFFER_FOR_ELEMENT:
|
||||
return "no buffer specified for an element in CompressedVectorNode "
|
||||
"during write "
|
||||
"(E57_ERROR_NO_BUFFER_FOR_ELEMENT)";
|
||||
case E57_ERROR_BUFFER_SIZE_MISMATCH:
|
||||
return "SourceDestBuffers not all same size "
|
||||
"(E57_ERROR_BUFFER_SIZE_MISMATCH)";
|
||||
case E57_ERROR_BUFFER_DUPLICATE_PATHNAME:
|
||||
"(ErrorValueNotRepresentable)";
|
||||
case ErrorScaledValueNotRepresentable:
|
||||
return "after scaling the result could not be represented in the requested type "
|
||||
"(ErrorScaledValueNotRepresentable)";
|
||||
case ErrorReal64TooLarge:
|
||||
return "a 64 bit IEEE float was too large to store in a 32 bit IEEE float "
|
||||
"(ErrorReal64TooLarge)";
|
||||
case ErrorExpectingNumeric:
|
||||
return "Expecting numeric representation in user's buffer, found ustring "
|
||||
"(ErrorExpectingNumeric)";
|
||||
case ErrorExpectingUString:
|
||||
return "Expecting string representation in user's buffer, found numeric "
|
||||
"(ErrorExpectingUString)";
|
||||
case ErrorInternal:
|
||||
return "An unrecoverable inconsistent internal state was detected (ErrorInternal)";
|
||||
case ErrorBadXMLFormat:
|
||||
return "E57 primitive not encoded in XML correctly (ErrorBadXMLFormat)";
|
||||
case ErrorXMLParser:
|
||||
return "XML not well formed (ErrorXMLParser)";
|
||||
case ErrorBadAPIArgument:
|
||||
return "bad API function argument provided by user (ErrorBadAPIArgument)";
|
||||
case ErrorFileReadOnly:
|
||||
return "can't modify read only file (ErrorFileReadOnly)";
|
||||
case ErrorBadChecksum:
|
||||
return "checksum mismatch, file is corrupted (ErrorBadChecksum)";
|
||||
case ErrorOpenFailed:
|
||||
return "open() failed (ErrorOpenFailed)";
|
||||
case ErrorCloseFailed:
|
||||
return "close() failed (ErrorCloseFailed)";
|
||||
case ErrorReadFailed:
|
||||
return "read() failed (ErrorReadFailed)";
|
||||
case ErrorWriteFailed:
|
||||
return "write() failed (ErrorWriteFailed)";
|
||||
case ErrorSeekFailed:
|
||||
return "lseek() failed (ErrorSeekFailed)";
|
||||
case ErrorPathUndefined:
|
||||
return "E57 element path well formed but not defined (ErrorPathUndefined)";
|
||||
case ErrorBadBuffer:
|
||||
return "bad SourceDestBuffer (ErrorBadBuffer)";
|
||||
case ErrorNoBufferForElement:
|
||||
return "no buffer specified for an element in CompressedVectorNode during write "
|
||||
"(ErrorNoBufferForElement)";
|
||||
case ErrorBufferSizeMismatch:
|
||||
return "SourceDestBuffers not all same size (ErrorBufferSizeMismatch)";
|
||||
case ErrorBufferDuplicatePathName:
|
||||
return "duplicate pathname in CompressedVectorNode read/write "
|
||||
"(E57_ERROR_BUFFER_DUPLICATE_PATHNAME)";
|
||||
case E57_ERROR_BAD_FILE_SIGNATURE:
|
||||
return "file signature not "
|
||||
"ASTM-E57"
|
||||
" (E57_ERROR_BAD_FILE_SIGNATURE)";
|
||||
case E57_ERROR_UNKNOWN_FILE_VERSION:
|
||||
return "incompatible file version (E57_ERROR_UNKNOWN_FILE_VERSION)";
|
||||
case E57_ERROR_BAD_FILE_LENGTH:
|
||||
return "size in file header not same as actual "
|
||||
"(E57_ERROR_BAD_FILE_LENGTH)";
|
||||
case E57_ERROR_XML_PARSER_INIT:
|
||||
return "XML parser failed to initialize (E57_ERROR_XML_PARSER_INIT)";
|
||||
case E57_ERROR_DUPLICATE_NAMESPACE_PREFIX:
|
||||
return "namespace prefix already defined "
|
||||
"(E57_ERROR_DUPLICATE_NAMESPACE_PREFIX)";
|
||||
case E57_ERROR_DUPLICATE_NAMESPACE_URI:
|
||||
return "namespace URI already defined "
|
||||
"(E57_ERROR_DUPLICATE_NAMESPACE_URI)";
|
||||
case E57_ERROR_BAD_PROTOTYPE:
|
||||
return "bad prototype in CompressedVectorNode "
|
||||
"(E57_ERROR_BAD_PROTOTYPE)";
|
||||
case E57_ERROR_BAD_CODECS:
|
||||
return "bad codecs in CompressedVectorNode (E57_ERROR_BAD_CODECS)";
|
||||
case E57_ERROR_VALUE_OUT_OF_BOUNDS:
|
||||
return "element value out of min/max bounds "
|
||||
"(E57_ERROR_VALUE_OUT_OF_BOUNDS)";
|
||||
case E57_ERROR_CONVERSION_REQUIRED:
|
||||
return "conversion required to assign element value, but not "
|
||||
"requested "
|
||||
"(E57_ERROR_CONVERSION_REQUIRED)";
|
||||
case E57_ERROR_BAD_PATH_NAME:
|
||||
return "E57 path name is not well formed (E57_ERROR_BAD_PATH_NAME)";
|
||||
case E57_ERROR_NOT_IMPLEMENTED:
|
||||
return "functionality not implemented (E57_ERROR_NOT_IMPLEMENTED)";
|
||||
case E57_ERROR_BAD_NODE_DOWNCAST:
|
||||
return "bad downcast from Node to specific node type "
|
||||
"(E57_ERROR_BAD_NODE_DOWNCAST)";
|
||||
case E57_ERROR_WRITER_NOT_OPEN:
|
||||
return "CompressedVectorWriter is no longer open "
|
||||
"(E57_ERROR_WRITER_NOT_OPEN)";
|
||||
case E57_ERROR_READER_NOT_OPEN:
|
||||
return "CompressedVectorReader is no longer open "
|
||||
"(E57_ERROR_READER_NOT_OPEN)";
|
||||
case E57_ERROR_NODE_UNATTACHED:
|
||||
return "node is not yet attached to tree of ImageFile "
|
||||
"(E57_ERROR_NODE_UNATTACHED)";
|
||||
case E57_ERROR_ALREADY_HAS_PARENT:
|
||||
return "node already has a parent (E57_ERROR_ALREADY_HAS_PARENT)";
|
||||
case E57_ERROR_DIFFERENT_DEST_IMAGEFILE:
|
||||
"(ErrorBufferDuplicatePathName)";
|
||||
case ErrorBadFileSignature:
|
||||
return "file signature not ASTM-E57 (ErrorBadFileSignature)";
|
||||
case ErrorUnknownFileVersion:
|
||||
return "incompatible file version (ErrorUnknownFileVersion)";
|
||||
case ErrorBadFileLength:
|
||||
return "size in file header not same as actual (ErrorBadFileLength)";
|
||||
case ErrorXMLParserInit:
|
||||
return "XML parser failed to initialize (ErrorXMLParserInit)";
|
||||
case ErrorDuplicateNamespacePrefix:
|
||||
return "namespace prefix already defined (ErrorDuplicateNamespacePrefix)";
|
||||
case ErrorDuplicateNamespaceURI:
|
||||
return "namespace URI already defined (ErrorDuplicateNamespaceURI)";
|
||||
case ErrorBadPrototype:
|
||||
return "bad prototype in CompressedVectorNode (ErrorBadPrototype)";
|
||||
case ErrorBadCodecs:
|
||||
return "bad codecs in CompressedVectorNode (ErrorBadCodecs)";
|
||||
case ErrorValueOutOfBounds:
|
||||
return "element value out of min/max bounds (ErrorValueOutOfBounds)";
|
||||
case ErrorConversionRequired:
|
||||
return "conversion required to assign element value, but not requested "
|
||||
"(ErrorConversionRequired)";
|
||||
case ErrorBadPathName:
|
||||
return "E57 path name is not well formed (ErrorBadPathName)";
|
||||
case ErrorNotImplemented:
|
||||
return "functionality not implemented (ErrorNotImplemented)";
|
||||
case ErrorBadNodeDowncast:
|
||||
return "bad downcast from Node to specific node type (ErrorBadNodeDowncast)";
|
||||
case ErrorWriterNotOpen:
|
||||
return "CompressedVectorWriter is no longer open (ErrorWriterNotOpen)";
|
||||
case ErrorReaderNotOpen:
|
||||
return "CompressedVectorReader is no longer open (ErrorReaderNotOpen)";
|
||||
case ErrorNodeUnattached:
|
||||
return "node is not yet attached to tree of ImageFile (ErrorNodeUnattached)";
|
||||
case ErrorAlreadyHasParent:
|
||||
return "node already has a parent (ErrorAlreadyHasParent)";
|
||||
case ErrorDifferentDestImageFile:
|
||||
return "nodes were constructed with different destImageFiles "
|
||||
"(E57_ERROR_DIFFERENT_DEST_IMAGEFILE)";
|
||||
case E57_ERROR_IMAGEFILE_NOT_OPEN:
|
||||
return "destImageFile is no longer open "
|
||||
"(E57_ERROR_IMAGEFILE_NOT_OPEN)";
|
||||
case E57_ERROR_BUFFERS_NOT_COMPATIBLE:
|
||||
"(ErrorDifferentDestImageFile)";
|
||||
case ErrorImageFileNotOpen:
|
||||
return "destImageFile is no longer open (ErrorImageFileNotOpen)";
|
||||
case ErrorBuffersNotCompatible:
|
||||
return "SourceDestBuffers not compatible with previously given ones "
|
||||
"(E57_ERROR_BUFFERS_NOT_COMPATIBLE)";
|
||||
case E57_ERROR_TOO_MANY_WRITERS:
|
||||
return "too many open CompressedVectorWriters of an ImageFile "
|
||||
"(E57_ERROR_TOO_MANY_WRITERS)";
|
||||
case E57_ERROR_TOO_MANY_READERS:
|
||||
return "too many open CompressedVectorReaders of an ImageFile "
|
||||
"(E57_ERROR_TOO_MANY_READERS)";
|
||||
case E57_ERROR_BAD_CONFIGURATION:
|
||||
return "bad configuration string (E57_ERROR_BAD_CONFIGURATION)";
|
||||
case E57_ERROR_INVARIANCE_VIOLATION:
|
||||
return "class invariance constraint violation in debug mode "
|
||||
"(E57_ERROR_INVARIANCE_VIOLATION)";
|
||||
"(ErrorBuffersNotCompatible)";
|
||||
case ErrorTooManyWriters:
|
||||
return "too many open CompressedVectorWriters of an ImageFile (ErrorTooManyWriters)";
|
||||
case ErrorTooManyReaders:
|
||||
return "too many open CompressedVectorReaders of an ImageFile (ErrorTooManyReaders)";
|
||||
case ErrorBadConfiguration:
|
||||
return "bad configuration string (ErrorBadConfiguration)";
|
||||
case ErrorInvarianceViolation:
|
||||
return "class invariance constraint violation in debug mode (ErrorInvarianceViolation)";
|
||||
case ErrorInvalidNodeType:
|
||||
return "an invalid node type was passed in Data3D pointFields (ErrorInvalidNodeType)";
|
||||
case ErrorInvalidData3DValue:
|
||||
return "an invalid value was passed in Data3D pointFields (ErrorInvalidData3DValue)";
|
||||
case ErrorData3DReadInvalidZeroRecords:
|
||||
return "trying to read an invalid Data3D with zero records - check for zero records "
|
||||
"before trying to read this Data3D section (ErrorInvalidZeroRecordsData3D)";
|
||||
|
||||
default:
|
||||
return "unknown error (" + std::to_string( ecode ) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
4891
src/3rdParty/libE57Format/src/E57Format.cpp
vendored
4891
src/3rdParty/libE57Format/src/E57Format.cpp
vendored
File diff suppressed because it is too large
Load Diff
239
src/3rdParty/libE57Format/src/E57SimpleData.cpp
vendored
239
src/3rdParty/libE57Format/src/E57SimpleData.cpp
vendored
@@ -1,25 +1,252 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Copyright (c) 2020 PTC Inc.
|
||||
// Copyright (c) 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
// for M_PI. This needs to be first, otherwise we might already include math header
|
||||
// without M_PI and we would get nothing because of the header guards.
|
||||
// For M_PI. This needs to be first, otherwise we might already include math header without M_PI and
|
||||
// we would get nothing because of the header guards.
|
||||
// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c)
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
|
||||
#include "E57SimpleData.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
/// @private
|
||||
/// Validates a Data3D and throws on error.
|
||||
constexpr void _validateData3D( const Data3D &inData3D )
|
||||
{
|
||||
if ( inData3D.pointFields.pointRangeNodeType == NumericalNodeType::Integer )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorInvalidNodeType, "pointRangeNodeType cannot be Integer" );
|
||||
}
|
||||
|
||||
// To avoid exposing M_PI, we define the constructor here.
|
||||
if ( inData3D.pointFields.angleNodeType == NumericalNodeType::Integer )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorInvalidNodeType, "angleNodeType cannot be Integer" );
|
||||
}
|
||||
}
|
||||
|
||||
/// To avoid exposing M_PI, we define the constructor here.
|
||||
SphericalBounds::SphericalBounds()
|
||||
{
|
||||
rangeMinimum = 0.;
|
||||
rangeMaximum = E57_DOUBLE_MAX;
|
||||
rangeMaximum = DOUBLE_MAX;
|
||||
azimuthStart = -M_PI;
|
||||
azimuthEnd = M_PI;
|
||||
elevationMinimum = -M_PI / 2.;
|
||||
elevationMaximum = M_PI / 2.;
|
||||
|
||||
constexpr auto HALF_PI = M_PI / 2.0;
|
||||
|
||||
elevationMinimum = -HALF_PI;
|
||||
elevationMaximum = HALF_PI;
|
||||
}
|
||||
|
||||
template <typename COORDTYPE>
|
||||
Data3DPointsData_t<COORDTYPE>::Data3DPointsData_t( Data3D &data3D ) : _selfAllocated( true )
|
||||
{
|
||||
static_assert( std::is_floating_point<COORDTYPE>::value, "Floating point type required." );
|
||||
|
||||
_validateData3D( data3D );
|
||||
|
||||
constexpr bool cIsFloat = std::is_same<COORDTYPE, float>::value;
|
||||
|
||||
// We need to adjust min/max for floats.
|
||||
if ( cIsFloat )
|
||||
{
|
||||
data3D.pointFields.pointRangeMinimum = FLOAT_MIN;
|
||||
data3D.pointFields.pointRangeMaximum = FLOAT_MAX;
|
||||
data3D.pointFields.angleMinimum = FLOAT_MIN;
|
||||
data3D.pointFields.angleMaximum = FLOAT_MAX;
|
||||
data3D.pointFields.timeMinimum = FLOAT_MIN;
|
||||
data3D.pointFields.timeMaximum = FLOAT_MAX;
|
||||
}
|
||||
|
||||
// IF point range node type is not ScaledInteger
|
||||
// THEN make sure the proper floating point type is set
|
||||
if ( data3D.pointFields.pointRangeNodeType != NumericalNodeType::ScaledInteger )
|
||||
{
|
||||
data3D.pointFields.pointRangeNodeType =
|
||||
( cIsFloat ? NumericalNodeType::Float : NumericalNodeType::Double );
|
||||
}
|
||||
|
||||
// IF angle node type is not ScaledInteger
|
||||
// THEN make sure the proper floating point type is set
|
||||
if ( data3D.pointFields.angleNodeType != NumericalNodeType::ScaledInteger )
|
||||
{
|
||||
data3D.pointFields.angleNodeType =
|
||||
( cIsFloat ? NumericalNodeType::Float : NumericalNodeType::Double );
|
||||
}
|
||||
|
||||
const auto cPointCount = data3D.pointCount;
|
||||
|
||||
if ( data3D.pointFields.cartesianXField )
|
||||
{
|
||||
cartesianX = new COORDTYPE[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.cartesianYField )
|
||||
{
|
||||
cartesianY = new COORDTYPE[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.cartesianZField )
|
||||
{
|
||||
cartesianZ = new COORDTYPE[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.cartesianInvalidStateField )
|
||||
{
|
||||
cartesianInvalidState = new int8_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.intensityField )
|
||||
{
|
||||
intensity = new double[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.isIntensityInvalidField )
|
||||
{
|
||||
isIntensityInvalid = new int8_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.colorRedField )
|
||||
{
|
||||
colorRed = new uint16_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.colorGreenField )
|
||||
{
|
||||
colorGreen = new uint16_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.colorBlueField )
|
||||
{
|
||||
colorBlue = new uint16_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.isColorInvalidField )
|
||||
{
|
||||
isColorInvalid = new int8_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.sphericalRangeField )
|
||||
{
|
||||
sphericalRange = new COORDTYPE[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.sphericalAzimuthField )
|
||||
{
|
||||
sphericalAzimuth = new COORDTYPE[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.sphericalElevationField )
|
||||
{
|
||||
sphericalElevation = new COORDTYPE[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.sphericalInvalidStateField )
|
||||
{
|
||||
sphericalInvalidState = new int8_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.rowIndexField )
|
||||
{
|
||||
rowIndex = new int32_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.columnIndexField )
|
||||
{
|
||||
columnIndex = new int32_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.returnIndexField )
|
||||
{
|
||||
returnIndex = new int8_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.returnCountField )
|
||||
{
|
||||
returnCount = new int8_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.timeStampField )
|
||||
{
|
||||
timeStamp = new double[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.isTimeStampInvalidField )
|
||||
{
|
||||
isTimeStampInvalid = new int8_t[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.normalXField )
|
||||
{
|
||||
normalX = new float[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.normalYField )
|
||||
{
|
||||
normalY = new float[cPointCount];
|
||||
}
|
||||
|
||||
if ( data3D.pointFields.normalZField )
|
||||
{
|
||||
normalZ = new float[cPointCount];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename COORDTYPE> Data3DPointsData_t<COORDTYPE>::~Data3DPointsData_t()
|
||||
{
|
||||
static_assert( std::is_floating_point<COORDTYPE>::value, "Floating point type required." );
|
||||
|
||||
if ( !_selfAllocated )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
delete[] cartesianX;
|
||||
delete[] cartesianY;
|
||||
delete[] cartesianZ;
|
||||
delete[] cartesianInvalidState;
|
||||
|
||||
delete[] intensity;
|
||||
delete[] isIntensityInvalid;
|
||||
|
||||
delete[] colorRed;
|
||||
delete[] colorGreen;
|
||||
delete[] colorBlue;
|
||||
delete[] isColorInvalid;
|
||||
|
||||
delete[] sphericalRange;
|
||||
delete[] sphericalAzimuth;
|
||||
delete[] sphericalElevation;
|
||||
delete[] sphericalInvalidState;
|
||||
|
||||
delete[] rowIndex;
|
||||
delete[] columnIndex;
|
||||
|
||||
delete[] returnIndex;
|
||||
delete[] returnCount;
|
||||
|
||||
delete[] timeStamp;
|
||||
delete[] isTimeStampInvalid;
|
||||
|
||||
delete[] normalX;
|
||||
delete[] normalY;
|
||||
delete[] normalZ;
|
||||
|
||||
// Set them all to nullptr.
|
||||
*this = Data3DPointsData_t<COORDTYPE>();
|
||||
}
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
template struct E57_DLL Data3DPointsData_t<float>;
|
||||
template struct E57_DLL Data3DPointsData_t<double>;
|
||||
#else
|
||||
template struct Data3DPointsData_t<float>;
|
||||
template struct Data3DPointsData_t<double>;
|
||||
#endif
|
||||
} // end namespace e57
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
|
||||
* Copyright (c) 2020 PTC Inc.
|
||||
* Copyright (c) 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
@@ -30,54 +31,67 @@
|
||||
|
||||
namespace e57
|
||||
{
|
||||
Reader::Reader( const ustring &filePath, const ReaderOptions &options ) :
|
||||
impl_( new ReaderImpl( filePath, options ) )
|
||||
{
|
||||
}
|
||||
|
||||
Reader::Reader( const ustring &filePath ) : impl_( new ReaderImpl( filePath ) )
|
||||
// Note that this constructor is deprecated (see header).
|
||||
Reader::Reader( const ustring &filePath ) : Reader( filePath, {} )
|
||||
{
|
||||
}
|
||||
|
||||
bool Reader::IsOpen() const
|
||||
{
|
||||
return impl_->IsOpen();
|
||||
};
|
||||
}
|
||||
|
||||
bool Reader::Close()
|
||||
{
|
||||
return impl_->Close();
|
||||
};
|
||||
}
|
||||
|
||||
bool Reader::GetE57Root( E57Root &fileHeader ) const
|
||||
{
|
||||
return impl_->GetE57Root( fileHeader );
|
||||
};
|
||||
}
|
||||
|
||||
int64_t Reader::GetImage2DCount() const
|
||||
{
|
||||
return impl_->GetImage2DCount();
|
||||
};
|
||||
}
|
||||
|
||||
bool Reader::ReadImage2D( int64_t imageIndex, Image2D &image2DHeader ) const
|
||||
{
|
||||
return impl_->ReadImage2D( imageIndex, image2DHeader );
|
||||
};
|
||||
}
|
||||
|
||||
bool Reader::GetImage2DSizes( int64_t imageIndex, Image2DProjection &imageProjection, Image2DType &imageType,
|
||||
int64_t &imageWidth, int64_t &imageHeight, int64_t &imageSize,
|
||||
Image2DType &imageMaskType, Image2DType &imageVisualType ) const
|
||||
bool Reader::GetImage2DSizes( int64_t imageIndex, Image2DProjection &imageProjection,
|
||||
Image2DType &imageType, int64_t &imageWidth, int64_t &imageHeight,
|
||||
int64_t &imageSize, Image2DType &imageMaskType,
|
||||
Image2DType &imageVisualType ) const
|
||||
{
|
||||
return impl_->GetImage2DSizes( imageIndex, imageProjection, imageType, imageWidth, imageHeight, imageSize,
|
||||
imageMaskType, imageVisualType );
|
||||
};
|
||||
return impl_->GetImage2DSizes( imageIndex, imageProjection, imageType, imageWidth,
|
||||
imageHeight, imageSize, imageMaskType, imageVisualType );
|
||||
}
|
||||
|
||||
int64_t Reader::ReadImage2DData( int64_t imageIndex, Image2DProjection imageProjection, Image2DType imageType,
|
||||
void *pBuffer, int64_t start, int64_t count ) const
|
||||
int64_t Reader::ReadImage2DData( int64_t imageIndex, Image2DProjection imageProjection,
|
||||
Image2DType imageType, void *pBuffer, int64_t start,
|
||||
int64_t count ) const
|
||||
{
|
||||
return impl_->ReadImage2DData( imageIndex, imageProjection, imageType, pBuffer, start, count );
|
||||
};
|
||||
auto *buffer = static_cast<uint8_t *>( pBuffer );
|
||||
const auto size = static_cast<size_t>( count );
|
||||
|
||||
const size_t read =
|
||||
impl_->ReadImage2DData( imageIndex, imageProjection, imageType, buffer, start, size );
|
||||
|
||||
return static_cast<int64_t>( read );
|
||||
}
|
||||
|
||||
int64_t Reader::GetData3DCount() const
|
||||
{
|
||||
return impl_->GetData3DCount();
|
||||
};
|
||||
}
|
||||
|
||||
ImageFile Reader::GetRawIMF() const
|
||||
{
|
||||
@@ -87,45 +101,47 @@ namespace e57
|
||||
StructureNode Reader::GetRawE57Root() const
|
||||
{
|
||||
return impl_->GetRawE57Root();
|
||||
};
|
||||
}
|
||||
|
||||
VectorNode Reader::GetRawData3D() const
|
||||
{
|
||||
return impl_->GetRawData3D();
|
||||
};
|
||||
}
|
||||
|
||||
VectorNode Reader::GetRawImages2D() const
|
||||
{
|
||||
return impl_->GetRawImages2D();
|
||||
};
|
||||
}
|
||||
|
||||
bool Reader::ReadData3D( int64_t dataIndex, Data3D &data3DHeader ) const
|
||||
{
|
||||
return impl_->ReadData3D( dataIndex, data3DHeader );
|
||||
}
|
||||
|
||||
bool Reader::GetData3DSizes( int64_t dataIndex, int64_t &rowMax, int64_t &columnMax, int64_t &pointsSize,
|
||||
int64_t &groupsSize, int64_t &countSize, bool &bColumnIndex ) const
|
||||
bool Reader::GetData3DSizes( int64_t dataIndex, int64_t &rowMax, int64_t &columnMax,
|
||||
int64_t &pointsSize, int64_t &groupsSize, int64_t &countSize,
|
||||
bool &bColumnIndex ) const
|
||||
{
|
||||
return impl_->GetData3DSizes( dataIndex, rowMax, columnMax, pointsSize, groupsSize, countSize, bColumnIndex );
|
||||
return impl_->GetData3DSizes( dataIndex, rowMax, columnMax, pointsSize, groupsSize, countSize,
|
||||
bColumnIndex );
|
||||
}
|
||||
|
||||
bool Reader::ReadData3DGroupsData( int64_t dataIndex, int64_t groupCount, int64_t *idElementValue,
|
||||
bool Reader::ReadData3DGroupsData( int64_t dataIndex, size_t groupCount, int64_t *idElementValue,
|
||||
int64_t *startPointIndex, int64_t *pointCount ) const
|
||||
{
|
||||
return impl_->ReadData3DGroupsData( dataIndex, groupCount, idElementValue, startPointIndex, pointCount );
|
||||
return impl_->ReadData3DGroupsData( dataIndex, groupCount, idElementValue, startPointIndex,
|
||||
pointCount );
|
||||
}
|
||||
|
||||
CompressedVectorReader Reader::SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsData &buffers ) const
|
||||
const Data3DPointsFloat &buffers ) const
|
||||
{
|
||||
return impl_->SetUpData3DPointsData( dataIndex, pointCount, buffers );
|
||||
}
|
||||
|
||||
CompressedVectorReader Reader::SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsData_d &buffers ) const
|
||||
const Data3DPointsDouble &buffers ) const
|
||||
{
|
||||
return impl_->SetUpData3DPointsData( dataIndex, pointCount, buffers );
|
||||
}
|
||||
|
||||
} // end namespace e57
|
||||
|
||||
255
src/3rdParty/libE57Format/src/E57SimpleWriter.cpp
vendored
255
src/3rdParty/libE57Format/src/E57SimpleWriter.cpp
vendored
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
|
||||
* Copyright (c) 2020 PTC Inc.
|
||||
* Copyright (c) 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
@@ -25,26 +26,233 @@
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "E57SimpleWriter.h"
|
||||
#include "WriterImpl.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
/// Fill in missing min/max data in the Data3D header for the following:
|
||||
/// - cartesian points
|
||||
/// - spherical points
|
||||
/// - time stamps
|
||||
template <typename COORDTYPE>
|
||||
void _fillMinMaxData( e57::Data3D &ioData3DHeader,
|
||||
const e57::Data3DPointsData_t<COORDTYPE> &inBuffers )
|
||||
{
|
||||
static_assert( std::is_floating_point<COORDTYPE>::value, "Floating point type required." );
|
||||
|
||||
auto &pointFields = ioData3DHeader.pointFields;
|
||||
|
||||
constexpr COORDTYPE cMin = std::numeric_limits<COORDTYPE>::lowest();
|
||||
constexpr COORDTYPE cMax = std::numeric_limits<COORDTYPE>::max();
|
||||
|
||||
// IF we are using scaled ints for cartesian points
|
||||
// AND we haven't set either min or max
|
||||
// THEN calculate them from the points
|
||||
auto pointRangeMinimum = cMax;
|
||||
auto pointRangeMaximum = cMin;
|
||||
|
||||
const bool writePointRange =
|
||||
( pointFields.pointRangeNodeType == e57::NumericalNodeType::ScaledInteger ) &&
|
||||
( pointFields.pointRangeMinimum == cMin ) && ( pointFields.pointRangeMaximum == cMax );
|
||||
|
||||
// IF we are using scaled ints for spherical angles
|
||||
// AND we haven't set either min or max
|
||||
// THEN calculate them from the points
|
||||
auto angleMinimum = cMax;
|
||||
auto angleMaximum = cMin;
|
||||
|
||||
const bool writeAngle =
|
||||
( pointFields.angleNodeType == e57::NumericalNodeType::ScaledInteger ) &&
|
||||
( pointFields.angleMinimum == cMin ) && ( pointFields.angleMaximum == cMax );
|
||||
|
||||
// IF we are using scaled ints for timestamps
|
||||
// AND we haven't set either min or max
|
||||
// THEN calculate them from the points
|
||||
double timeMinimum = std::numeric_limits<double>::max();
|
||||
double timeMaximum = std::numeric_limits<double>::lowest();
|
||||
|
||||
const bool writeTimeStamp =
|
||||
pointFields.timeStampField &&
|
||||
( pointFields.timeNodeType == e57::NumericalNodeType::ScaledInteger ) &&
|
||||
( pointFields.timeMinimum == cMin ) && ( pointFields.timeMaximum == cMax );
|
||||
|
||||
// Now run through the points and set the things we need to
|
||||
for ( size_t i = 0; i < ioData3DHeader.pointCount; ++i )
|
||||
{
|
||||
if ( writePointRange && pointFields.cartesianXField )
|
||||
{
|
||||
pointRangeMinimum = std::min( inBuffers.cartesianX[i], pointRangeMinimum );
|
||||
pointRangeMinimum = std::min( inBuffers.cartesianY[i], pointRangeMinimum );
|
||||
pointRangeMinimum = std::min( inBuffers.cartesianZ[i], pointRangeMinimum );
|
||||
|
||||
pointRangeMaximum = std::max( inBuffers.cartesianX[i], pointRangeMaximum );
|
||||
pointRangeMaximum = std::max( inBuffers.cartesianY[i], pointRangeMaximum );
|
||||
pointRangeMaximum = std::max( inBuffers.cartesianZ[i], pointRangeMaximum );
|
||||
}
|
||||
|
||||
if ( writePointRange && pointFields.sphericalRangeField )
|
||||
{
|
||||
// Note that the writer code uses pointRangeMinimum/pointRangeMaximum
|
||||
// (see WriterImpl::NewData3D()) instead of using the sphericalBounds which has
|
||||
// rangeMinimum and rangeMaximum.
|
||||
pointRangeMinimum = std::min( inBuffers.sphericalRange[i], pointRangeMinimum );
|
||||
pointRangeMaximum = std::max( inBuffers.sphericalRange[i], pointRangeMaximum );
|
||||
}
|
||||
|
||||
if ( writeAngle )
|
||||
{
|
||||
angleMinimum = std::min( inBuffers.sphericalAzimuth[i], angleMinimum );
|
||||
angleMinimum = std::min( inBuffers.sphericalElevation[i], angleMinimum );
|
||||
|
||||
angleMaximum = std::max( inBuffers.sphericalAzimuth[i], angleMaximum );
|
||||
angleMaximum = std::max( inBuffers.sphericalElevation[i], angleMaximum );
|
||||
}
|
||||
|
||||
if ( writeTimeStamp )
|
||||
{
|
||||
timeMinimum = std::min( inBuffers.timeStamp[i], timeMinimum );
|
||||
timeMaximum = std::max( inBuffers.timeStamp[i], timeMaximum );
|
||||
}
|
||||
}
|
||||
|
||||
if ( writePointRange )
|
||||
{
|
||||
pointFields.pointRangeMinimum = pointRangeMinimum;
|
||||
pointFields.pointRangeMaximum = pointRangeMaximum;
|
||||
}
|
||||
|
||||
if ( writeAngle )
|
||||
{
|
||||
pointFields.angleMinimum = angleMinimum;
|
||||
pointFields.angleMaximum = angleMaximum;
|
||||
}
|
||||
|
||||
if ( writeTimeStamp )
|
||||
{
|
||||
pointFields.timeMinimum = timeMinimum;
|
||||
pointFields.timeMaximum = timeMaximum;
|
||||
}
|
||||
}
|
||||
template void _fillMinMaxData( e57::Data3D &ioData3DHeader,
|
||||
const e57::Data3DPointsFloat &inBuffers );
|
||||
template void _fillMinMaxData( e57::Data3D &ioData3DHeader,
|
||||
const e57::Data3DPointsDouble &inBuffers );
|
||||
}
|
||||
|
||||
namespace e57
|
||||
{
|
||||
Writer::Writer( const ustring &filePath, const WriterOptions &options ) :
|
||||
impl_( new WriterImpl( filePath, options ) )
|
||||
{
|
||||
}
|
||||
|
||||
Writer::Writer( const ustring &filePath, const ustring &coordinateMetaData ) :
|
||||
impl_( new WriterImpl( filePath, coordinateMetaData ) )
|
||||
// Note that this constructor is deprecated (see header).
|
||||
Writer::Writer( const ustring &filePath, const ustring &coordinateMetadata ) :
|
||||
Writer( filePath, WriterOptions{ {}, coordinateMetadata } )
|
||||
{
|
||||
}
|
||||
|
||||
bool Writer::IsOpen() const
|
||||
{
|
||||
return impl_->IsOpen();
|
||||
};
|
||||
}
|
||||
|
||||
bool Writer::Close()
|
||||
{
|
||||
return impl_->Close();
|
||||
};
|
||||
}
|
||||
|
||||
int64_t Writer::WriteImage2DData( Image2D &image2DHeader, Image2DType imageType,
|
||||
Image2DProjection imageProjection, int64_t startPos,
|
||||
void *pBuffer, int64_t byteCount )
|
||||
{
|
||||
auto *buffer = static_cast<uint8_t *>( pBuffer );
|
||||
const auto sizeInBytes = static_cast<size_t>( byteCount );
|
||||
|
||||
const int64_t imageIndex = impl_->NewImage2D( image2DHeader );
|
||||
|
||||
const size_t written = impl_->WriteImage2DData( imageIndex, imageType, imageProjection,
|
||||
buffer, startPos, sizeInBytes );
|
||||
|
||||
return static_cast<int64_t>( written );
|
||||
}
|
||||
|
||||
int64_t Writer::NewImage2D( Image2D &image2DHeader )
|
||||
{
|
||||
return impl_->NewImage2D( image2DHeader );
|
||||
}
|
||||
|
||||
int64_t Writer::WriteImage2DData( int64_t imageIndex, Image2DType imageType,
|
||||
Image2DProjection imageProjection, void *pBuffer,
|
||||
int64_t start, int64_t count )
|
||||
{
|
||||
auto *buffer = static_cast<uint8_t *>( pBuffer );
|
||||
const auto size = static_cast<size_t>( count );
|
||||
|
||||
const size_t written =
|
||||
impl_->WriteImage2DData( imageIndex, imageType, imageProjection, buffer, start, size );
|
||||
|
||||
return static_cast<int64_t>( written );
|
||||
}
|
||||
|
||||
int64_t Writer::WriteData3DData( Data3D &data3DHeader, const Data3DPointsFloat &buffers )
|
||||
{
|
||||
_fillMinMaxData( data3DHeader, buffers );
|
||||
|
||||
const int64_t scanIndex = impl_->NewData3D( data3DHeader );
|
||||
|
||||
e57::CompressedVectorWriter dataWriter =
|
||||
impl_->SetUpData3DPointsData( scanIndex, data3DHeader.pointCount, buffers );
|
||||
|
||||
dataWriter.write( data3DHeader.pointCount );
|
||||
dataWriter.close();
|
||||
|
||||
return scanIndex;
|
||||
}
|
||||
|
||||
int64_t Writer::WriteData3DData( Data3D &data3DHeader, const Data3DPointsDouble &buffers )
|
||||
{
|
||||
_fillMinMaxData( data3DHeader, buffers );
|
||||
|
||||
const int64_t scanIndex = impl_->NewData3D( data3DHeader );
|
||||
|
||||
e57::CompressedVectorWriter dataWriter =
|
||||
impl_->SetUpData3DPointsData( scanIndex, data3DHeader.pointCount, buffers );
|
||||
|
||||
dataWriter.write( data3DHeader.pointCount );
|
||||
dataWriter.close();
|
||||
|
||||
return scanIndex;
|
||||
}
|
||||
|
||||
int64_t Writer::NewData3D( Data3D &data3DHeader )
|
||||
{
|
||||
return impl_->NewData3D( data3DHeader );
|
||||
}
|
||||
|
||||
CompressedVectorWriter Writer::SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsFloat &buffers )
|
||||
{
|
||||
return impl_->SetUpData3DPointsData( dataIndex, pointCount, buffers );
|
||||
}
|
||||
|
||||
CompressedVectorWriter Writer::SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsDouble &buffers )
|
||||
{
|
||||
return impl_->SetUpData3DPointsData( dataIndex, pointCount, buffers );
|
||||
}
|
||||
|
||||
bool Writer::WriteData3DGroupsData( int64_t dataIndex, size_t groupCount,
|
||||
int64_t *idElementValue, int64_t *startPointIndex,
|
||||
int64_t *pointCount )
|
||||
{
|
||||
return impl_->WriteData3DGroupsData( dataIndex, groupCount, idElementValue, startPointIndex,
|
||||
pointCount );
|
||||
}
|
||||
|
||||
ImageFile Writer::GetRawIMF()
|
||||
{
|
||||
@@ -54,50 +262,15 @@ namespace e57
|
||||
StructureNode Writer::GetRawE57Root()
|
||||
{
|
||||
return impl_->GetRawE57Root();
|
||||
};
|
||||
}
|
||||
|
||||
VectorNode Writer::GetRawData3D()
|
||||
{
|
||||
return impl_->GetRawData3D();
|
||||
};
|
||||
}
|
||||
|
||||
VectorNode Writer::GetRawImages2D()
|
||||
{
|
||||
return impl_->GetRawImages2D();
|
||||
};
|
||||
|
||||
int64_t Writer::NewImage2D( Image2D &image2DHeader )
|
||||
{
|
||||
return impl_->NewImage2D( image2DHeader );
|
||||
};
|
||||
|
||||
int64_t Writer::WriteImage2DData( int64_t imageIndex, Image2DType imageType, Image2DProjection imageProjection,
|
||||
void *pBuffer, int64_t start, int64_t count )
|
||||
{
|
||||
return impl_->WriteImage2DData( imageIndex, imageType, imageProjection, pBuffer, start, count );
|
||||
};
|
||||
|
||||
int64_t Writer::NewData3D( Data3D &data3DHeader )
|
||||
{
|
||||
return impl_->NewData3D( data3DHeader );
|
||||
};
|
||||
|
||||
CompressedVectorWriter Writer::SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsData &buffers )
|
||||
{
|
||||
return impl_->SetUpData3DPointsData( dataIndex, pointCount, buffers );
|
||||
}
|
||||
|
||||
CompressedVectorWriter Writer::SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsData_d &buffers )
|
||||
{
|
||||
return impl_->SetUpData3DPointsData( dataIndex, pointCount, buffers );
|
||||
}
|
||||
|
||||
bool Writer::WriteData3DGroupsData( int64_t dataIndex, int64_t groupCount, int64_t *idElementValue,
|
||||
int64_t *startPointIndex, int64_t *pointCount )
|
||||
{
|
||||
return impl_->WriteData3DGroupsData( dataIndex, groupCount, idElementValue, startPointIndex, pointCount );
|
||||
}
|
||||
|
||||
} // end namespace e57
|
||||
|
||||
55
src/3rdParty/libE57Format/src/E57Version.cpp
vendored
Normal file
55
src/3rdParty/libE57Format/src/E57Version.cpp
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Copyright 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "ASTMVersion.h"
|
||||
#include "E57Version.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
// REVISION_ID should be passed from compiler command line
|
||||
#ifndef REVISION_ID
|
||||
#error "Need to specify REVISION_ID on command line"
|
||||
#endif
|
||||
|
||||
std::string Version::astm()
|
||||
{
|
||||
std::ostringstream stringStream;
|
||||
stringStream << E57_FORMAT_MAJOR << "." << E57_FORMAT_MINOR;
|
||||
return stringStream.str();
|
||||
}
|
||||
|
||||
uint32_t Version::astmMajor()
|
||||
{
|
||||
return E57_FORMAT_MAJOR;
|
||||
}
|
||||
|
||||
uint32_t Version::astmMinor()
|
||||
{
|
||||
return E57_FORMAT_MINOR;
|
||||
}
|
||||
|
||||
std::string Version::library()
|
||||
{
|
||||
return REVISION_ID;
|
||||
}
|
||||
|
||||
void Version::get( uint32_t &astmMajor, uint32_t &astmMinor, std::string &libraryId )
|
||||
{
|
||||
astmMajor = E57_FORMAT_MAJOR;
|
||||
astmMinor = E57_FORMAT_MINOR;
|
||||
libraryId = REVISION_ID;
|
||||
}
|
||||
|
||||
namespace Utilities
|
||||
{
|
||||
void getVersions( int &astmMajor, int &astmMinor, std::string &libraryId )
|
||||
{
|
||||
astmMajor = E57_FORMAT_MAJOR;
|
||||
astmMinor = E57_FORMAT_MINOR;
|
||||
libraryId = REVISION_ID;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
src/3rdParty/libE57Format/src/E57Version.h
vendored
12
src/3rdParty/libE57Format/src/E57Version.h
vendored
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace e57
|
||||
{
|
||||
/// Version numbers of ASTM standard that this library supports
|
||||
constexpr uint32_t E57_FORMAT_MAJOR = 1;
|
||||
constexpr uint32_t E57_FORMAT_MINOR = 0;
|
||||
}
|
||||
1889
src/3rdParty/libE57Format/src/E57XmlParser.cpp
vendored
1889
src/3rdParty/libE57Format/src/E57XmlParser.cpp
vendored
File diff suppressed because it is too large
Load Diff
249
src/3rdParty/libE57Format/src/E57XmlParser.h
vendored
249
src/3rdParty/libE57Format/src/E57XmlParser.h
vendored
@@ -1,126 +1,123 @@
|
||||
/*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <stack>
|
||||
|
||||
#include <xercesc/sax/InputSource.hpp>
|
||||
#include <xercesc/sax2/DefaultHandler.hpp>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
using namespace XERCES_CPP_NAMESPACE;
|
||||
|
||||
namespace XERCES_CPP_NAMESPACE
|
||||
{
|
||||
class SAX2XMLReader;
|
||||
}
|
||||
|
||||
namespace e57
|
||||
{
|
||||
class CheckedFile;
|
||||
|
||||
class E57XmlParser : public DefaultHandler
|
||||
{
|
||||
public:
|
||||
E57XmlParser( ImageFileImplSharedPtr imf );
|
||||
~E57XmlParser() override;
|
||||
|
||||
void init();
|
||||
|
||||
void parse( InputSource &inputSource );
|
||||
|
||||
private:
|
||||
/// SAX interface
|
||||
void startElement( const XMLCh *const uri, const XMLCh *const localName, const XMLCh *const qName,
|
||||
const Attributes &attributes ) override;
|
||||
void endElement( const XMLCh *const uri, const XMLCh *const localName, const XMLCh *const qName ) override;
|
||||
void characters( const XMLCh *const chars, const XMLSize_t length ) override;
|
||||
|
||||
/// SAX error interface
|
||||
void warning( const SAXParseException &ex ) override;
|
||||
void error( const SAXParseException &ex ) override;
|
||||
void fatalError( const SAXParseException &ex ) override;
|
||||
|
||||
ustring toUString( const XMLCh *const xml_str );
|
||||
ustring lookupAttribute( const Attributes &attributes, const XMLCh *attribute_name );
|
||||
bool isAttributeDefined( const Attributes &attributes, const XMLCh *attribute_name );
|
||||
|
||||
ImageFileImplSharedPtr imf_; /// Image file we are reading
|
||||
|
||||
struct ParseInfo
|
||||
{
|
||||
/// All the fields need to remember while parsing the XML
|
||||
/// Not all fields are used at same time, depends on node type
|
||||
/// Needed because not all info is available at one time to create the
|
||||
/// node.
|
||||
NodeType nodeType; // used by all types
|
||||
int64_t minimum; // used in E57_INTEGER, E57_SCALED_INTEGER
|
||||
int64_t maximum; // used in E57_INTEGER, E57_SCALED_INTEGER
|
||||
double scale; // used in E57_SCALED_INTEGER
|
||||
double offset; // used in E57_SCALED_INTEGER
|
||||
FloatPrecision precision; // used in E57_FLOAT
|
||||
double floatMinimum; // used in E57_FLOAT
|
||||
double floatMaximum; // used in E57_FLOAT
|
||||
int64_t fileOffset; // used in E57_BLOB, E57_COMPRESSED_VECTOR
|
||||
int64_t length; // used in E57_BLOB
|
||||
bool allowHeterogeneousChildren; // used in E57_VECTOR
|
||||
int64_t recordCount; // used in E57_COMPRESSED_VECTOR
|
||||
ustring childText; // used by all types, accumulates all child text between tags
|
||||
|
||||
/// Holds node for Structure, Vector, and CompressedVector so can append
|
||||
/// child elements
|
||||
NodeImplSharedPtr container_ni;
|
||||
|
||||
ParseInfo(); // default ctor
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
};
|
||||
std::stack<ParseInfo> stack_; /// Stores the current path in tree we are reading
|
||||
|
||||
SAX2XMLReader *xmlReader;
|
||||
};
|
||||
|
||||
class E57XmlFileInputSource : public InputSource
|
||||
{
|
||||
public:
|
||||
E57XmlFileInputSource( CheckedFile *cf, uint64_t logicalStart, uint64_t logicalLength );
|
||||
~E57XmlFileInputSource() override = default;
|
||||
|
||||
E57XmlFileInputSource( const E57XmlFileInputSource & ) = delete;
|
||||
E57XmlFileInputSource &operator=( const E57XmlFileInputSource & ) = delete;
|
||||
|
||||
BinInputStream *makeStream() const override;
|
||||
|
||||
private:
|
||||
//??? lifetime of cf_ must be longer than this object!
|
||||
CheckedFile *cf_;
|
||||
uint64_t logicalStart_;
|
||||
uint64_t logicalLength_;
|
||||
};
|
||||
}
|
||||
/*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <stack>
|
||||
|
||||
#include <xercesc/sax/InputSource.hpp>
|
||||
#include <xercesc/sax2/DefaultHandler.hpp>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
using namespace XERCES_CPP_NAMESPACE;
|
||||
|
||||
namespace XERCES_CPP_NAMESPACE
|
||||
{
|
||||
class SAX2XMLReader;
|
||||
}
|
||||
|
||||
namespace e57
|
||||
{
|
||||
class CheckedFile;
|
||||
|
||||
class E57XmlParser : public DefaultHandler
|
||||
{
|
||||
public:
|
||||
explicit E57XmlParser( ImageFileImplSharedPtr imf );
|
||||
~E57XmlParser() override;
|
||||
|
||||
void init();
|
||||
|
||||
void parse( InputSource &inputSource );
|
||||
|
||||
private:
|
||||
/// SAX interface
|
||||
void startElement( const XMLCh *uri, const XMLCh *localName, const XMLCh *qName,
|
||||
const Attributes &attributes ) override;
|
||||
void endElement( const XMLCh *uri, const XMLCh *localName, const XMLCh *qName ) override;
|
||||
void characters( const XMLCh *chars, XMLSize_t length ) override;
|
||||
|
||||
/// SAX error interface
|
||||
void warning( const SAXParseException &ex ) override;
|
||||
void error( const SAXParseException &ex ) override;
|
||||
void fatalError( const SAXParseException &ex ) override;
|
||||
|
||||
ImageFileImplSharedPtr imf_; /// Image file we are reading
|
||||
|
||||
struct ParseInfo
|
||||
{
|
||||
// All the fields need to remember while parsing the XML
|
||||
// Not all fields are used at same time, depends on node type
|
||||
// Needed because not all info is available at one time to create the
|
||||
// node.
|
||||
NodeType nodeType; // used by all types
|
||||
int64_t minimum; // used in Integer, ScaledInteger
|
||||
int64_t maximum; // used in Integer, ScaledInteger
|
||||
double scale; // used in ScaledInteger
|
||||
double offset; // used in ScaledInteger
|
||||
FloatPrecision precision; // used in Float
|
||||
double floatMinimum; // used in Float
|
||||
double floatMaximum; // used in Float
|
||||
int64_t fileOffset; // used in Blob, CompressedVector
|
||||
int64_t length; // used in Blob
|
||||
bool allowHeterogeneousChildren; // used in Vector
|
||||
int64_t recordCount; // used in CompressedVector
|
||||
ustring childText; // used by all types, accumulates all child text between tags
|
||||
|
||||
// Holds node for Structure, Vector, and CompressedVector so can append
|
||||
// child elements
|
||||
NodeImplSharedPtr container_ni;
|
||||
|
||||
ParseInfo(); // default ctor
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
};
|
||||
|
||||
std::stack<ParseInfo> stack_; /// Stores the current path in tree we are reading
|
||||
|
||||
SAX2XMLReader *xmlReader;
|
||||
};
|
||||
|
||||
class E57XmlFileInputSource : public InputSource
|
||||
{
|
||||
public:
|
||||
E57XmlFileInputSource( CheckedFile *cf, uint64_t logicalStart, uint64_t logicalLength );
|
||||
~E57XmlFileInputSource() override = default;
|
||||
|
||||
E57XmlFileInputSource( const E57XmlFileInputSource & ) = delete;
|
||||
E57XmlFileInputSource &operator=( const E57XmlFileInputSource & ) = delete;
|
||||
|
||||
BinInputStream *makeStream() const override;
|
||||
|
||||
private:
|
||||
//??? lifetime of cf_ must be longer than this object!
|
||||
CheckedFile *cf_;
|
||||
uint64_t logicalStart_;
|
||||
uint64_t logicalLength_;
|
||||
};
|
||||
}
|
||||
|
||||
512
src/3rdParty/libE57Format/src/Encoder.cpp
vendored
512
src/3rdParty/libE57Format/src/Encoder.cpp
vendored
File diff suppressed because it is too large
Load Diff
52
src/3rdParty/libE57Format/src/Encoder.h
vendored
52
src/3rdParty/libE57Format/src/Encoder.h
vendored
@@ -34,9 +34,9 @@ namespace e57
|
||||
class Encoder
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<Encoder> EncoderFactory( unsigned bytestreamNumber,
|
||||
std::shared_ptr<CompressedVectorNodeImpl> cVector,
|
||||
std::vector<SourceDestBuffer> &sbuf, ustring &codecPath );
|
||||
static std::shared_ptr<Encoder> EncoderFactory(
|
||||
unsigned bytestreamNumber, std::shared_ptr<CompressedVectorNodeImpl> cVector,
|
||||
std::vector<SourceDestBuffer> &sbuf, ustring &codecPath );
|
||||
|
||||
virtual ~Encoder() = default;
|
||||
|
||||
@@ -46,8 +46,8 @@ namespace e57
|
||||
virtual float bitsPerRecord() = 0;
|
||||
virtual bool registerFlushToOutput() = 0;
|
||||
|
||||
virtual size_t outputAvailable() const = 0; /// number of bytes that can be read
|
||||
virtual void outputRead( char *dest, const size_t byteCount ) = 0; /// get data from encoder
|
||||
virtual size_t outputAvailable() const = 0; /// number of bytes that can be read
|
||||
virtual void outputRead( char *dest, size_t byteCount ) = 0; /// get data from encoder
|
||||
virtual void outputClear() = 0;
|
||||
|
||||
virtual void sourceBufferSetNew( std::vector<SourceDestBuffer> &sbufs ) = 0;
|
||||
@@ -59,11 +59,12 @@ namespace e57
|
||||
return bytestreamNumber_;
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
virtual void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Encoder( unsigned bytestreamNumber );
|
||||
explicit Encoder( unsigned bytestreamNumber );
|
||||
|
||||
unsigned bytestreamNumber_;
|
||||
};
|
||||
@@ -77,18 +78,18 @@ namespace e57
|
||||
float bitsPerRecord() override = 0;
|
||||
bool registerFlushToOutput() override = 0;
|
||||
|
||||
size_t outputAvailable() const override; /// number of bytes that can be read
|
||||
void outputRead( char *dest,
|
||||
const size_t byteCount ) override; /// get data from encoder
|
||||
size_t outputAvailable() const override; /// number of bytes that can be read
|
||||
void outputRead( char *dest, size_t byteCount ) override; /// get data from encoder
|
||||
void outputClear() override;
|
||||
|
||||
void sourceBufferSetNew( std::vector<SourceDestBuffer> &sbufs ) override;
|
||||
size_t outputGetMaxSize() override;
|
||||
void outputSetMaxSize( unsigned byteCount ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
BitpackEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf, unsigned outputMaxSize,
|
||||
unsigned alignmentSize );
|
||||
@@ -108,16 +109,17 @@ namespace e57
|
||||
class BitpackFloatEncoder : public BitpackEncoder
|
||||
{
|
||||
public:
|
||||
BitpackFloatEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf, unsigned outputMaxSize,
|
||||
FloatPrecision precision );
|
||||
BitpackFloatEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf,
|
||||
unsigned outputMaxSize, FloatPrecision precision );
|
||||
|
||||
uint64_t processRecords( size_t recordCount ) override;
|
||||
bool registerFlushToOutput() override;
|
||||
float bitsPerRecord() override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
FloatPrecision precision_;
|
||||
};
|
||||
@@ -125,15 +127,17 @@ namespace e57
|
||||
class BitpackStringEncoder : public BitpackEncoder
|
||||
{
|
||||
public:
|
||||
BitpackStringEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf, unsigned outputMaxSize );
|
||||
BitpackStringEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf,
|
||||
unsigned outputMaxSize );
|
||||
|
||||
uint64_t processRecords( size_t recordCount ) override;
|
||||
bool registerFlushToOutput() override;
|
||||
float bitsPerRecord() override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
uint64_t totalBytesProcessed_;
|
||||
bool isStringActive_;
|
||||
@@ -145,16 +149,18 @@ namespace e57
|
||||
template <typename RegisterT> class BitpackIntegerEncoder : public BitpackEncoder
|
||||
{
|
||||
public:
|
||||
BitpackIntegerEncoder( bool isScaledInteger, unsigned bytestreamNumber, SourceDestBuffer &sbuf,
|
||||
unsigned outputMaxSize, int64_t minimum, int64_t maximum, double scale, double offset );
|
||||
BitpackIntegerEncoder( bool isScaledInteger, unsigned bytestreamNumber,
|
||||
SourceDestBuffer &sbuf, unsigned outputMaxSize, int64_t minimum,
|
||||
int64_t maximum, double scale, double offset );
|
||||
|
||||
uint64_t processRecords( size_t recordCount ) override;
|
||||
bool registerFlushToOutput() override;
|
||||
float bitsPerRecord() override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool isScaledInteger_;
|
||||
int64_t minimum_;
|
||||
@@ -177,18 +183,18 @@ namespace e57
|
||||
float bitsPerRecord() override;
|
||||
bool registerFlushToOutput() override;
|
||||
|
||||
size_t outputAvailable() const override; /// number of bytes that can be read
|
||||
void outputRead( char *dest,
|
||||
const size_t byteCount ) override; /// get data from encoder
|
||||
size_t outputAvailable() const override; /// number of bytes that can be read
|
||||
void outputRead( char *dest, size_t byteCount ) override; /// get data from encoder
|
||||
void outputClear() override;
|
||||
|
||||
void sourceBufferSetNew( std::vector<SourceDestBuffer> &sbufs ) override;
|
||||
size_t outputGetMaxSize() override;
|
||||
void outputSetMaxSize( unsigned byteCount ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::shared_ptr<SourceDestBufferImpl> sourceBuffer_;
|
||||
uint64_t currentRecordIndex_;
|
||||
|
||||
362
src/3rdParty/libE57Format/src/FloatNode.cpp
vendored
Normal file
362
src/3rdParty/libE57Format/src/FloatNode.cpp
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* FloatNode.cpp - implementation of public functions of the FloatNode class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file FloatNode.cpp
|
||||
|
||||
#include "FloatNodeImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Putting this function first so we can reference the code in doxygen using @skip
|
||||
/// @brief Check whether FloatNode class invariant is true
|
||||
/// @copydetails IntegerNode::checkInvariant()
|
||||
void FloatNode::checkInvariant( bool /*doRecurse*/, bool doUpcast ) const
|
||||
{
|
||||
// If destImageFile not open, can't test invariant (almost every call would throw)
|
||||
if ( !destImageFile().isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If requested, call Node::checkInvariant
|
||||
if ( doUpcast )
|
||||
{
|
||||
static_cast<Node>( *this ).checkInvariant( false, false );
|
||||
}
|
||||
|
||||
if ( precision() == PrecisionSingle )
|
||||
{
|
||||
if ( static_cast<float>( minimum() ) < FLOAT_MIN ||
|
||||
static_cast<float>( maximum() ) > FLOAT_MAX )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
// If value is out of bounds
|
||||
if ( value() < minimum() || value() > maximum() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::FloatNode
|
||||
|
||||
@brief An E57 element encoding a single or double precision IEEE floating point number.
|
||||
|
||||
@details
|
||||
An FloatNode is a terminal node (i.e. having no children) that holds an IEEE floating point value,
|
||||
and minimum/maximum bounds. The precision of the floating point value and attributes may be either
|
||||
single or double precision. Once the FloatNode value and attributes are set at creation, they may
|
||||
not be modified.
|
||||
|
||||
If the precision option of the FloatNode is Single:
|
||||
The minimum attribute may be a number in the interval [-3.402823466e+38, 3.402823466e+38]. The
|
||||
maximum attribute may be a number in the interval [maximum, 3.402823466e+38]. The value may be a
|
||||
number in the interval [minimum, maximum].
|
||||
|
||||
If the precision option of the FloatNode is Double:
|
||||
The minimum attribute may be a number in the interval
|
||||
[-1.7976931348623158e+308, 1.7976931348623158e+308]. The maximum attribute may be a number in the
|
||||
interval [maximum, 1.7976931348623158e+308]. The value may be a number in the interval [minimum,
|
||||
maximum].
|
||||
|
||||
See Node class discussion for discussion of the common functions that StructureNode supports.
|
||||
|
||||
@section FloatNode_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude FloatNode.cpp
|
||||
@skip void FloatNode::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see Node
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Create an E57 element for storing an double precision IEEE floating point number.
|
||||
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
@param [in] value The double precision IEEE floating point value of the element.
|
||||
@param [in] precision The precision of IEEE floating point to use. May be ::PrecisionSingle or
|
||||
::PrecisionDouble.
|
||||
@param [in] minimum The smallest value that the value may take.
|
||||
@param [in] maximum The largest value that the value may take.
|
||||
|
||||
@details
|
||||
An FloatNode stores an IEEE floating point number and a lower and upper bound. The FloatNode class
|
||||
corresponds to the ASTM E57 standard Float element. See the class discussion at bottom of FloatNode
|
||||
page for more details.
|
||||
|
||||
The @a destImageFile indicates which ImageFile the FloatNode will eventually be attached to. A node
|
||||
is attached to an ImageFile by adding it underneath the predefined root of the ImageFile (gotten
|
||||
from ImageFile::root). It is not an error to fail to attach the FloatNode to the @a destImageFile.
|
||||
It is an error to attempt to attach the FloatNode to a different ImageFile.
|
||||
|
||||
There is only one FloatNode constructor that handles both ::PrecisionSingle and ::PrecisionDouble
|
||||
precision cases. If @a precision = ::PrecisionSingle, then the object will silently round the double
|
||||
precision @a value to the nearest representable single precision value. In this case, the lower bits
|
||||
will be lost, and if the value is outside the representable range of a single precision number, the
|
||||
exponent may be changed. The same is true for the @a minimum and @a maximum arguments.
|
||||
|
||||
@warning It is an error to give an @a value outside the @a minimum / @a maximum bounds, even if the
|
||||
FloatNode is destined to be used in a CompressedVectorNode prototype (where the @a value will be
|
||||
ignored). If the FloatNode is to be used in a prototype, it is recommended to specify a @a value = 0
|
||||
if 0 is within bounds, or a @a value = @a minimum if 0 is not within bounds.
|
||||
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
@pre minimum <= value <= maximum
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorValueOutOfBounds
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see FloatPrecision, FloatNode::value, Node, CompressedVectorNode, CompressedVectorNode::prototype
|
||||
*/
|
||||
FloatNode::FloatNode( const ImageFile &destImageFile, double value, FloatPrecision precision,
|
||||
double minimum, double maximum ) :
|
||||
impl_( new FloatNodeImpl( destImageFile.impl(), value, precision, minimum, maximum ) )
|
||||
{
|
||||
impl_->validateValue();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is this a root node.
|
||||
@copydetails Node::isRoot()
|
||||
*/
|
||||
bool FloatNode::isRoot() const
|
||||
{
|
||||
return impl_->isRoot();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return parent of node, or self if a root node.
|
||||
@copydetails Node::parent()
|
||||
*/
|
||||
Node FloatNode::parent() const
|
||||
{
|
||||
return Node( impl_->parent() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get absolute pathname of node.
|
||||
@copydetails Node::pathName()
|
||||
*/
|
||||
ustring FloatNode::pathName() const
|
||||
{
|
||||
return impl_->pathName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get elementName string, that identifies the node in its parent.
|
||||
@copydetails Node::elementName()
|
||||
*/
|
||||
ustring FloatNode::elementName() const
|
||||
{
|
||||
return impl_->elementName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the ImageFile that was declared as the destination for the node when it was created.
|
||||
@copydetails Node::destImageFile()
|
||||
*/
|
||||
ImageFile FloatNode::destImageFile() const
|
||||
{
|
||||
return ImageFile( impl_->destImageFile() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Has node been attached into the tree of an ImageFile.
|
||||
@copydetails Node::isAttached()
|
||||
*/
|
||||
bool FloatNode::isAttached() const
|
||||
{
|
||||
return impl_->isAttached();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get IEEE floating point value stored.
|
||||
|
||||
@details
|
||||
If precision is ::PrecisionSingle, the single precision value is returned as a double. If precision
|
||||
is ::PrecisionDouble, the double precision value is returned as a double.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The IEEE floating point value stored, represented as a double.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see FloatNode::minimum, FloatNode::maximum
|
||||
*/
|
||||
double FloatNode::value() const
|
||||
{
|
||||
return impl_->value();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get declared precision of the floating point number.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The declared precision of the floating point number, either ::PrecisionSingle or
|
||||
::PrecisionDouble.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see FloatPrecision
|
||||
*/
|
||||
FloatPrecision FloatNode::precision() const
|
||||
{
|
||||
return impl_->precision();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the declared minimum that the value may take.
|
||||
|
||||
@details
|
||||
If precision is ::PrecisionSingle, the single precision minimum is returned as a double. If
|
||||
precision is ::PrecisionDouble, the double precision minimum is returned as a double.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The declared minimum that the value may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see FloatNode::maximum, FloatNode::value
|
||||
*/
|
||||
double FloatNode::minimum() const
|
||||
{
|
||||
return impl_->minimum();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the declared maximum that the value may take.
|
||||
|
||||
@details
|
||||
If precision is ::PrecisionSingle, the single precision maximum is returned as a double. If
|
||||
precision is ::PrecisionDouble, the double precision maximum is returned as a double.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The declared maximum that the value may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see FloatNode::minimum, FloatNode::value
|
||||
*/
|
||||
double FloatNode::maximum() const
|
||||
{
|
||||
return impl_->maximum();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void FloatNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void FloatNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Upcast a FloatNode handle to a generic Node handle.
|
||||
|
||||
@details An upcast is always safe, and the compiler can automatically insert it for initializations
|
||||
of Node variables and Node function arguments.
|
||||
|
||||
@return A smart Node handle referencing the underlying object.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see Explanation in Node, Node::type()
|
||||
*/
|
||||
FloatNode::operator Node() const
|
||||
{
|
||||
// Upcast from shared_ptr<FloatNodeImpl> to SharedNodeImplPtr and construct a Node object
|
||||
return Node( impl_ );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Downcast a generic Node handle to a FloatNode handle.
|
||||
|
||||
@param [in] n The generic handle to downcast.
|
||||
|
||||
@details
|
||||
The handle @a n must be for an underlying FloatNode, otherwise an exception is thrown. In designs
|
||||
that need to avoid the exception, use Node::type() to determine the actual type of the @a n before
|
||||
downcasting. This function must be explicitly called (c++ compiler cannot insert it automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
|
||||
@see Node::type(), FloatNode::operator Node()
|
||||
*/
|
||||
FloatNode::FloatNode( const Node &n )
|
||||
{
|
||||
if ( n.type() != TypeFloat )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadNodeDowncast, "nodeType=" + toString( n.type() ) );
|
||||
}
|
||||
|
||||
// Set our shared_ptr to the downcast shared_ptr
|
||||
impl_ = std::static_pointer_cast<FloatNodeImpl>( n.impl() );
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
FloatNode::FloatNode( std::shared_ptr<FloatNodeImpl> ni ) : impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
99
src/3rdParty/libE57Format/src/FloatNodeImpl.cpp
vendored
99
src/3rdParty/libE57Format/src/FloatNodeImpl.cpp
vendored
@@ -27,37 +27,39 @@
|
||||
|
||||
#include "FloatNodeImpl.h"
|
||||
#include "CheckedFile.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
FloatNodeImpl::FloatNodeImpl( ImageFileImplWeakPtr destImageFile, double value, FloatPrecision precision,
|
||||
double minimum, double maximum ) :
|
||||
NodeImpl( destImageFile ),
|
||||
value_( value ), precision_( precision ), minimum_( minimum ), maximum_( maximum )
|
||||
FloatNodeImpl::FloatNodeImpl( ImageFileImplWeakPtr destImageFile, double value,
|
||||
FloatPrecision precision, double minimum, double maximum ) :
|
||||
NodeImpl( destImageFile ), value_( value ), precision_( precision ), minimum_( minimum ),
|
||||
maximum_( maximum )
|
||||
{
|
||||
// don't checkImageFileOpen, NodeImpl() will do it
|
||||
|
||||
/// Since this ctor also used to construct single precision, and defaults for
|
||||
/// minimum/maximum are for double precision, adjust bounds smaller if
|
||||
/// single.
|
||||
if ( precision_ == E57_SINGLE )
|
||||
// Since this ctor also used to construct single precision, and defaults for minimum/maximum
|
||||
// are for double precision, adjust bounds smaller if single.
|
||||
if ( precision_ == PrecisionSingle )
|
||||
{
|
||||
if ( minimum_ < E57_FLOAT_MIN )
|
||||
if ( minimum_ < FLOAT_MIN )
|
||||
{
|
||||
minimum_ = E57_FLOAT_MIN;
|
||||
minimum_ = FLOAT_MIN;
|
||||
}
|
||||
if ( maximum_ > E57_FLOAT_MAX )
|
||||
if ( maximum_ > FLOAT_MAX )
|
||||
{
|
||||
maximum_ = E57_FLOAT_MAX;
|
||||
maximum_ = FLOAT_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enforce the given bounds on raw value
|
||||
if ( value < minimum || maximum < value )
|
||||
// Throw an exception if the value is not within bounds.
|
||||
void FloatNodeImpl::validateValue() const
|
||||
{
|
||||
if ( value_ < minimum_ || value_ > maximum_ )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_VALUE_OUT_OF_BOUNDS,
|
||||
"this->pathName=" + this->pathName() + " value=" + toString( value ) +
|
||||
" minimum=" + toString( minimum ) + " maximum=" + toString( maximum ) );
|
||||
throw E57_EXCEPTION2( ErrorValueOutOfBounds, "this->pathName=" + this->pathName() +
|
||||
" value=" + toString( value_ ) +
|
||||
" minimum=" + toString( minimum_ ) +
|
||||
" maximum=" + toString( maximum_ ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,36 +67,36 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// Same node type?
|
||||
if ( ni->type() != E57_FLOAT )
|
||||
// Same node type?
|
||||
if ( ni->type() != TypeFloat )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// Downcast to shared_ptr<FloatNodeImpl>
|
||||
// Downcast to shared_ptr<FloatNodeImpl>
|
||||
std::shared_ptr<FloatNodeImpl> fi( std::static_pointer_cast<FloatNodeImpl>( ni ) );
|
||||
|
||||
/// precision must match
|
||||
// precision must match
|
||||
if ( precision_ != fi->precision_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// minimum must match
|
||||
// minimum must match
|
||||
if ( minimum_ != fi->minimum_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// maximum must match
|
||||
// maximum must match
|
||||
if ( maximum_ != fi->maximum_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// ignore value_, doesn't have to match
|
||||
// ignore value_, doesn't have to match
|
||||
|
||||
/// Types match
|
||||
// Types match
|
||||
return ( true );
|
||||
}
|
||||
|
||||
@@ -102,7 +104,7 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// We have no sub-structure, so if path not empty return false
|
||||
// We have no sub-structure, so if path not empty return false
|
||||
return pathName.empty();
|
||||
}
|
||||
|
||||
@@ -134,12 +136,11 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// We are a leaf node, so verify that we are listed in set (either relative
|
||||
/// or absolute form)
|
||||
// We are a leaf node, so verify that we are listed in set (either relative or absolute form)
|
||||
if ( pathNames.find( relativePathName( origin ) ) == pathNames.end() &&
|
||||
pathNames.find( pathName() ) == pathNames.end() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_NO_BUFFER_FOR_ELEMENT, "this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorNoBufferForElement, "this->pathName=" + this->pathName() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +150,7 @@ namespace e57
|
||||
// don't checkImageFileOpen
|
||||
|
||||
ustring fieldName;
|
||||
if ( forcedFieldName )
|
||||
if ( forcedFieldName != nullptr )
|
||||
{
|
||||
fieldName = forcedFieldName;
|
||||
}
|
||||
@@ -159,21 +160,21 @@ namespace e57
|
||||
}
|
||||
|
||||
cf << space( indent ) << "<" << fieldName << " type=\"Float\"";
|
||||
if ( precision_ == E57_SINGLE )
|
||||
if ( precision_ == PrecisionSingle )
|
||||
{
|
||||
cf << " precision=\"single\"";
|
||||
|
||||
/// Don't need to write if are default values
|
||||
if ( minimum_ > E57_FLOAT_MIN )
|
||||
// Don't need to write if are default values
|
||||
if ( minimum_ > FLOAT_MIN )
|
||||
{
|
||||
cf << " minimum=\"" << static_cast<float>( minimum_ ) << "\"";
|
||||
}
|
||||
if ( maximum_ < E57_FLOAT_MAX )
|
||||
if ( maximum_ < FLOAT_MAX )
|
||||
{
|
||||
cf << " maximum=\"" << static_cast<float>( maximum_ ) << "\"";
|
||||
}
|
||||
|
||||
/// Write value as child text, unless it is the default value
|
||||
// Write value as child text, unless it is the default value
|
||||
if ( value_ != 0.0 )
|
||||
{
|
||||
cf << ">" << static_cast<float>( value_ ) << "</" << fieldName << ">\n";
|
||||
@@ -185,19 +186,19 @@ namespace e57
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Don't need to write precision="double", because that's the default
|
||||
// Don't need to write precision="double", because that's the default
|
||||
|
||||
/// Don't need to write if are default values
|
||||
if ( minimum_ > E57_DOUBLE_MIN )
|
||||
// Don't need to write if are default values
|
||||
if ( minimum_ > DOUBLE_MIN )
|
||||
{
|
||||
cf << " minimum=\"" << minimum_ << "\"";
|
||||
}
|
||||
if ( maximum_ < E57_DOUBLE_MAX )
|
||||
if ( maximum_ < DOUBLE_MAX )
|
||||
{
|
||||
cf << " maximum=\"" << maximum_ << "\"";
|
||||
}
|
||||
|
||||
/// Write value as child text, unless it is the default value
|
||||
// Write value as child text, unless it is the default value
|
||||
if ( value_ != 0.0 )
|
||||
{
|
||||
cf << ">" << value_ << "</" << fieldName << ">\n";
|
||||
@@ -209,15 +210,14 @@ namespace e57
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void FloatNodeImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
os << space( indent ) << "type: Float"
|
||||
<< " (" << type() << ")" << std::endl;
|
||||
os << space( indent ) << "type: Float" << " (" << type() << ")" << std::endl;
|
||||
NodeImpl::dump( indent, os );
|
||||
os << space( indent ) << "precision: ";
|
||||
if ( precision() == E57_SINGLE )
|
||||
if ( precision() == PrecisionSingle )
|
||||
{
|
||||
os << "single" << std::endl;
|
||||
}
|
||||
@@ -226,15 +226,16 @@ namespace e57
|
||||
os << "double" << std::endl;
|
||||
}
|
||||
|
||||
/// Save old stream config
|
||||
// Save old stream config
|
||||
const std::streamsize oldPrecision = os.precision();
|
||||
const std::ios_base::fmtflags oldFlags = os.flags();
|
||||
|
||||
os << space( indent ) << std::scientific << std::setprecision( 17 ) << "value: " << value_ << std::endl;
|
||||
os << space( indent ) << std::scientific << std::setprecision( 17 )
|
||||
<< "value: " << value_ << std::endl;
|
||||
os << space( indent ) << "minimum: " << minimum_ << std::endl;
|
||||
os << space( indent ) << "maximum: " << maximum_ << std::endl;
|
||||
|
||||
/// Restore old stream config
|
||||
// Restore old stream config
|
||||
os.precision( oldPrecision );
|
||||
os.flags( oldFlags );
|
||||
}
|
||||
|
||||
11
src/3rdParty/libE57Format/src/FloatNodeImpl.h
vendored
11
src/3rdParty/libE57Format/src/FloatNodeImpl.h
vendored
@@ -33,14 +33,17 @@ namespace e57
|
||||
class FloatNodeImpl : public NodeImpl
|
||||
{
|
||||
public:
|
||||
FloatNodeImpl( ImageFileImplWeakPtr destImageFile, double value = 0, FloatPrecision precision = E57_DOUBLE,
|
||||
double minimum = E57_DOUBLE_MIN, double maximum = E57_DOUBLE_MAX );
|
||||
FloatNodeImpl( ImageFileImplWeakPtr destImageFile, double value, FloatPrecision precision,
|
||||
double minimum, double maximum );
|
||||
~FloatNodeImpl() override = default;
|
||||
|
||||
NodeType type() const override
|
||||
{
|
||||
return E57_FLOAT;
|
||||
return TypeFloat;
|
||||
}
|
||||
|
||||
void validateValue() const;
|
||||
|
||||
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
|
||||
bool isDefined( const ustring &pathName ) override;
|
||||
|
||||
@@ -54,7 +57,7 @@ namespace e57
|
||||
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
|
||||
const char *forcedFieldName = nullptr ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
|
||||
771
src/3rdParty/libE57Format/src/ImageFile.cpp
vendored
Normal file
771
src/3rdParty/libE57Format/src/ImageFile.cpp
vendored
Normal file
@@ -0,0 +1,771 @@
|
||||
/*
|
||||
* ImageFile.cpp - implementation of public functions of the ImageFile class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file ImageFile.cpp
|
||||
|
||||
#include "ImageFileImpl.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether ImageFile class invariant is true
|
||||
|
||||
@param [in] doRecurse If true, also check invariants of all children or sub-objects recursively.
|
||||
|
||||
@details
|
||||
This function checks at least the assertions in the documented class invariant description (see
|
||||
class reference page for this object). Other internal invariants that are implementation-dependent
|
||||
may also be checked. If any invariant clause is violated, an E57Exception with errorCode of
|
||||
ErrorInvarianceViolation is thrown.
|
||||
|
||||
Checking the invariant recursively may be expensive if the tree is large, so should be used
|
||||
judiciously, in debug versions of the application.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@throw ::ErrorInvarianceViolation or any other E57 ErrorCode
|
||||
|
||||
@see Node::checkInvariant
|
||||
*/
|
||||
void ImageFile::checkInvariant( bool doRecurse ) const
|
||||
{
|
||||
// If this ImageFile is not open, can't test invariant (almost every call
|
||||
// would throw)
|
||||
if ( !isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// root() node must be a root node
|
||||
if ( !root().isRoot() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Can't have empty fileName
|
||||
if ( fileName().empty() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
int wCount = writerCount();
|
||||
int rCount = readerCount();
|
||||
|
||||
// Can't have negative number of readers
|
||||
if ( rCount < 0 )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Can't have negative number of writers
|
||||
if ( wCount < 0 )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Can't have more than one writer
|
||||
if ( 1 < wCount )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// If have writer
|
||||
if ( wCount > 0 )
|
||||
{
|
||||
// Must be in write-mode
|
||||
if ( !isWritable() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Can't have any readers
|
||||
if ( rCount > 0 )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
// Extension prefixes and URIs are unique
|
||||
const size_t eCount = extensionsCount();
|
||||
for ( size_t i = 0; i < eCount; i++ )
|
||||
{
|
||||
for ( size_t j = i + 1; j < eCount; j++ )
|
||||
{
|
||||
if ( extensionsPrefix( i ) == extensionsPrefix( j ) )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
if ( extensionsUri( i ) == extensionsUri( j ) )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify lookup functions are correct
|
||||
for ( size_t i = 0; i < eCount; i++ )
|
||||
{
|
||||
ustring goodPrefix = extensionsPrefix( i );
|
||||
ustring goodUri = extensionsUri( i );
|
||||
ustring prefix;
|
||||
ustring uri;
|
||||
if ( !extensionsLookupPrefix( goodPrefix, uri ) )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
if ( uri != goodUri )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
if ( !extensionsLookupUri( goodUri, prefix ) )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
if ( prefix != goodPrefix )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
// If requested, check all objects "below" this one
|
||||
if ( doRecurse )
|
||||
{
|
||||
root().checkInvariant( doRecurse );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::ImageFile
|
||||
|
||||
@brief An ASTM E57 3D format file object.
|
||||
|
||||
@details
|
||||
@section imagefile_ClassOverview Class overview
|
||||
The ImageFile class represents the state of an ASTM E57 format data file. An ImageFile may be
|
||||
created from an E57 file on the disk (read mode). An new ImageFile may be created to write an E57
|
||||
file to disk (write mode).
|
||||
|
||||
E57 files are organized in a tree structure.
|
||||
Each ImageFile object has a predefined root node (of type StructureNode). In a write mode ImageFile,
|
||||
the root node is initially empty. In a read mode ImageFile, the root node is populated by the tree
|
||||
stored in the .e57 file on disk.
|
||||
|
||||
@section imagefile_OpenClose The open/close state
|
||||
An ImageFile object, opened in either mode (read/write), can be in one of two states: open or
|
||||
closed. An ImageFile in the open state is ready to perform transfers of data and to be interrogated.
|
||||
An ImageFile in the closed state cannot perform any further transfers, and has very limited ability
|
||||
to be interrogated. Note entering the closed state is different than destroying the ImageFile
|
||||
object. An ImageFile object can still exist and be in the closed state. When created, the ImageFile
|
||||
is initially open.
|
||||
|
||||
The ImageFile state can transition to the closed state in two ways. The programmer can call
|
||||
ImageFile::close after all required processing has completed. The programmer can call
|
||||
ImageFile::cancel if it is determined that the ImageFile is no longer needed.
|
||||
|
||||
@section imagefile_Extensions Extensions
|
||||
Basically in an E57 file, "extension = namespace + rules + meaning".
|
||||
The "namespace" ensures that element names don't collide.
|
||||
The "rules" may be written on paper, or partly codified in a computer grammar.
|
||||
The "meaning" is a definition of what was measured, what the numbers in the file mean.
|
||||
|
||||
Extensions are identified by URIs.
|
||||
Extensions are not identified by prefixes.
|
||||
Prefixes are a shorthand, used in a particular file, to make the element names more palatable for
|
||||
humans. When thinking about a prefixed element name, in your mind you should immediately substitute
|
||||
the URI for the prefix. For example, think "http://www.example.com/DemoExtension:extra2" rather than
|
||||
"demo:extra2", if the prefix "demo" is declared in the file to be a shorthand for the URI
|
||||
"http://www.example.com/DemoExtension".
|
||||
|
||||
The rules are statements of: what is valid, what element names are possible, what values are
|
||||
possible. The rules establish the answer to the following yes/no question: "Is this extended E57
|
||||
file valid?". The rules divide all possible files into two sets: valid files and invalid files.
|
||||
|
||||
The "meanings" part of the above equation defines what the files in the first set, the valid files,
|
||||
actually mean. This definition usually comes in the form of documentation of the content of each new
|
||||
element in the format and how they relate to the other elements.
|
||||
|
||||
An element name in an E57 file is a member of exactly one namespace (either the default namespace
|
||||
defined in the ASTM standard, or an extension namespace). Rules about the structure of an E57
|
||||
extension (what element names can appear where), are implicitly assumed only to govern the element
|
||||
names within the namespace of the extension. Element names in other namespaces are unconstrained.
|
||||
This is because a reader is required to ignore elements in namespaces that are unfamiliar (to treat
|
||||
them as if they didn't exist). This enables a writer to "tack on" new elements into pre-defined
|
||||
structures (e.g. structures defined in the ASTM standard), without fear that it will confuse a
|
||||
reader that is only familiar with the old format. This allows an extension designer to communicate
|
||||
to two sets of readers: the old readers that will understand the information in the old base format,
|
||||
and the new-fangled readers that will be able to read the base format and the extra information
|
||||
stored in element names in the extended namespace.
|
||||
|
||||
@section ImageFile_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude ImageFile.cpp
|
||||
@skip void ImageFile::checkInvariant
|
||||
@until ^}
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Open an ASTM E57 imaging data file for reading/writing.
|
||||
|
||||
@param [in] fname File name to open.
|
||||
Support of '\' as a directory separating character is system dependent. For maximum portability, it
|
||||
is recommended that '/' be used as a directory separator in file names. Special device file name
|
||||
support are implementation dependent (e.g. "\\.\PhysicalDrive3" or "/dev/hd3"). It is recommended
|
||||
that files that meet all of the requirements for a legal ASTM E57 file format use the extension @c
|
||||
".e57". It is recommended that files that utilize the low-level E57 element data types, but do not
|
||||
have all the required element names required by ASTM E57 file format standard use the file extension
|
||||
@c "._e57".
|
||||
@param [in] mode Either "w" for writing or "r" for reading.
|
||||
@param [in] checksumPolicy The percentage of checksums we compute and verify as an int. Clamped to
|
||||
0-100.
|
||||
|
||||
@par Write Mode
|
||||
In write mode, the file cannot be already open.
|
||||
A file with name given by @a fname is immediately created on the disk.
|
||||
This file may grow as a result of operations on the ImageFile.
|
||||
Which API functions write data to the file are implementation dependent.
|
||||
Thus any API operation that stores data may fail as a result of insufficient free disk space. Read
|
||||
API operations are legal for an ImageFile opened in write mode.
|
||||
|
||||
@par Read Mode
|
||||
Read mode files may be shared.
|
||||
Write API operations are not legal for an ImageFile opened in read mode (i.e. the ImageFile is
|
||||
read-only). There is no API support for appending data onto an existing E57 data file.
|
||||
|
||||
@post Resulting ImageFile is in @c open state if constructor succeeds (no exception thrown).
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorOpenFailed
|
||||
@throw ::ErrorSeekFailed
|
||||
@throw ::ErrorReadFailed
|
||||
@throw ::ErrorWriteFailed
|
||||
@throw ::ErrorBadChecksum
|
||||
@throw ::ErrorBadFileSignature
|
||||
@throw ::ErrorUnknownFileVersion
|
||||
@throw ::ErrorBadFileLength
|
||||
@throw ::ErrorXMLParserInit
|
||||
@throw ::ErrorXMLParser
|
||||
@throw ::ErrorBadXMLFormat
|
||||
@throw ::ErrorBadConfiguration
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see IntegerNode, ScaledIntegerNode, FloatNode, StringNode, BlobNode, StructureNode, VectorNode,
|
||||
CompressedVectorNode, E57Exception, E57Utilities::E57Utilities
|
||||
*/
|
||||
ImageFile::ImageFile( const ustring &fname, const ustring &mode,
|
||||
ReadChecksumPolicy checksumPolicy ) :
|
||||
impl_( new ImageFileImpl( checksumPolicy ) )
|
||||
{
|
||||
// Do second phase of construction, now that ImageFile object is complete.
|
||||
impl_->construct2( fname, mode );
|
||||
}
|
||||
|
||||
ImageFile::ImageFile( const char *input, const uint64_t size, ReadChecksumPolicy checksumPolicy ) :
|
||||
impl_( new ImageFileImpl( checksumPolicy ) )
|
||||
{
|
||||
impl_->construct2( input, size );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the pre-established root StructureNode of the E57 ImageFile.
|
||||
|
||||
@details The root node of an ImageFile always exists and is always type StructureNode. The root node
|
||||
is empty in a newly created write mode ImageFile.
|
||||
|
||||
@pre This ImageFile must be open (i.e. isOpen()).
|
||||
|
||||
@return A smart StructureNode handle referencing the underlying object.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StructureNode.
|
||||
*/
|
||||
StructureNode ImageFile::root() const
|
||||
{
|
||||
return StructureNode( impl_->root() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Complete any write operations on an ImageFile, and close the file on the disk.
|
||||
|
||||
@details
|
||||
Completes the writing of the state of the ImageFile to the disk.
|
||||
Some API implementations may store significant portions of the state of the ImageFile in memory.
|
||||
This state is moved into the disk file before it is closed. Any errors in finishing the writing are
|
||||
reported by throwing an exception. If an exception is thrown, depending on the error code, the
|
||||
ImageFile may enter the closed state. If no exception is thrown, then the file on disk will be an
|
||||
accurate representation of the ImageFile.
|
||||
|
||||
@warning If the ImageFile::close function is not called, and the ImageFile destructor is invoked
|
||||
with the ImageFile in the open state, the associated disk file will be deleted and the ImageFile
|
||||
will @em not be saved to the disk (the same outcome as calling ImageFile::cancel). The reason for
|
||||
this is that any error conditions can't be reported from a destructor, so the user can't be assured
|
||||
that the destruction/close completed successfully. It is strongly recommended that this close
|
||||
function be called before the ImageFile is destroyed.
|
||||
|
||||
It is not an error if ImageFile is already closed.
|
||||
|
||||
@post ImageFile is in @c closed state.
|
||||
|
||||
@throw ::ErrorSeekFailed
|
||||
@throw ::ErrorReadFailed
|
||||
@throw ::ErrorWriteFailed
|
||||
@throw ::ErrorCloseFailed
|
||||
@throw ::ErrorBadChecksum
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::cancel, ImageFile::isOpen
|
||||
*/
|
||||
void ImageFile::close()
|
||||
{
|
||||
impl_->close();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Stop I/O operations and delete a partially written ImageFile on the disk.
|
||||
|
||||
@details
|
||||
If the ImageFile is write mode, the associated file on the disk is closed and deleted, and the
|
||||
ImageFile goes to the closed state. If the ImageFile is read mode, the behavior is same as calling
|
||||
ImageFile::close, but no exceptions are thrown. It is not an error if ImageFile is already closed.
|
||||
|
||||
@post ImageFile is in @c closed state.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see ImageFile::ImageFile, ImageFile::close, ImageFile::isOpen
|
||||
*/
|
||||
void ImageFile::cancel()
|
||||
{
|
||||
impl_->cancel();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Test whether ImageFile is still open for accessing.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return true if ImageFile is in @c open state.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see ImageFile::ImageFile, ImageFile::close
|
||||
*/
|
||||
bool ImageFile::isOpen() const
|
||||
{
|
||||
return impl_->isOpen();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Test whether ImageFile was opened in write mode.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return true if ImageFile was opened in write mode.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see ImageFile::ImageFile, ImageFile::isOpen
|
||||
*/
|
||||
bool ImageFile::isWritable() const
|
||||
{
|
||||
return impl_->isWriter();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the file name the ImageFile was created with.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The file name the ImageFile was created with.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see ImageFile::ImageFile
|
||||
*/
|
||||
ustring ImageFile::fileName() const
|
||||
{
|
||||
return impl_->fileName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get current number of open CompressedVectorWriter objects writing to ImageFile.
|
||||
|
||||
@details
|
||||
CompressedVectorWriter objects that still exist, but are in the closed state aren't counted.
|
||||
CompressedVectorWriter objects are created by the CompressedVectorNode::writer function.
|
||||
|
||||
@pre This ImageFile must be open (i.e. isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The current number of open CompressedVectorWriter objects writing to ImageFile.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::writer, CompressedVectorWriter
|
||||
*/
|
||||
int ImageFile::writerCount() const
|
||||
{
|
||||
return impl_->writerCount();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get current number of open CompressedVectorReader objects reading from ImageFile.
|
||||
|
||||
@details
|
||||
CompressedVectorReader objects that still exist, but are in the closed state aren't counted.
|
||||
CompressedVectorReader objects are created by the CompressedVectorNode::reader function.
|
||||
|
||||
@pre This ImageFile must be open (i.e. isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The current number of open CompressedVectorReader objects reading from ImageFile.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::reader, CompressedVectorReader
|
||||
*/
|
||||
int ImageFile::readerCount() const
|
||||
{
|
||||
return impl_->readerCount();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Declare the use of an E57 extension in an ImageFile being written.
|
||||
|
||||
@param [in] prefix The shorthand name of the extension to use in element names.
|
||||
@param [in] uri The Uniform Resource Identifier string to associate with the prefix in the
|
||||
ImageFile.
|
||||
|
||||
@details
|
||||
The (@a prefix, @a uri) pair is registered in the known extensions of the ImageFile. Both @a prefix
|
||||
and @a uri must be unique in the ImageFile. It is not legal to declare a URI associated with the
|
||||
default namespace (@a prefix = ""). It is not an error to declare a namespace and not use it in an
|
||||
element name. It is an error to use a namespace prefix in an element name that is not declared
|
||||
beforehand.
|
||||
|
||||
A writer is free to "hard code" the prefix names in the element name strings that it uses (since it
|
||||
established the prefix declarations in the file). A reader cannot assume that any given prefix is
|
||||
always mapped to the same URI or vice versa. A reader might check an ImageFile, and if the prefixes
|
||||
aren't the way it likes, the reader could give up.
|
||||
|
||||
A better scheme would be to lookup the URI that the reader is familiar with, and store the prefix
|
||||
that the particular file uses in a variable. Then every time the reader needs to form a prefixed
|
||||
element name, it can assemble the full element name from the stored prefix variable and the constant
|
||||
documented base name string. This is less convenient than using a single "hard coded" string
|
||||
constant for an element name, but it is robust against any choice of prefix/URI combination.
|
||||
|
||||
See the class discussion at bottom of ImageFile page for more details about namespaces.
|
||||
|
||||
@pre This ImageFile must be open (i.e. isOpen()).
|
||||
@pre ImageFile must have been opened in write mode (i.e. isWritable()).
|
||||
@pre prefix != ""
|
||||
@pre uri != ""
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorDuplicateNamespacePrefix
|
||||
@throw ::ErrorDuplicateNamespaceURI
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsCount, ImageFile::extensionsLookupPrefix, ImageFile::extensionsLookupUri
|
||||
*/
|
||||
void ImageFile::extensionsAdd( const ustring &prefix, const ustring &uri )
|
||||
{
|
||||
impl_->extensionsAdd( prefix, uri );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Look up an E57 extension prefix in the ImageFile.
|
||||
|
||||
@param [in] prefix The shorthand name of the extension to look up.
|
||||
|
||||
@details
|
||||
If @a prefix = "" or @a prefix is declared in the ImageFile, then the function returns true. It is
|
||||
an error if @a prefix contains an illegal character combination for E57 namespace prefixes.
|
||||
|
||||
@pre This ImageFile must be open (i.e. isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return true if prefix is declared in the ImageFile.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsLookupUri
|
||||
*/
|
||||
bool ImageFile::extensionsLookupPrefix( const ustring &prefix ) const
|
||||
{
|
||||
ustring uri;
|
||||
return impl_->extensionsLookupPrefix( prefix, uri );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get URI associated with an E57 extension prefix in the ImageFile.
|
||||
|
||||
@param [in] prefix The shorthand name of the extension to look up.
|
||||
@param [out] uri The URI that was associated with the given @a prefix.
|
||||
|
||||
@details
|
||||
If @a prefix = "", then @a uri is set to the default namespace URI, and the function returns true.
|
||||
if @a prefix is declared in the ImageFile, then @a uri is set the corresponding URI, and the
|
||||
function returns true. It is an error if @a prefix contains an illegal character combination for E57
|
||||
namespace prefixes. It is not an error if @a prefix is well-formed, but not defined in the ImageFile
|
||||
(the function just returns false).
|
||||
|
||||
@pre This ImageFile must be open (i.e. isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return true if prefix is declared in the ImageFile.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsLookupUri
|
||||
*/
|
||||
bool ImageFile::extensionsLookupPrefix( const ustring &prefix, ustring &uri ) const
|
||||
{
|
||||
return impl_->extensionsLookupPrefix( prefix, uri );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get an E57 extension prefix associated with a URI in the ImageFile.
|
||||
|
||||
@param [in] uri The URI of the extension to look up.
|
||||
@param [out] prefix The shorthand prefix that was associated with the given @a uri.
|
||||
|
||||
@details
|
||||
If @a uri is declared in the ImageFile, then @a prefix is set the corresponding prefix, and the
|
||||
function returns true. It is an error if @a uri contains an illegal character combination for E57
|
||||
namespace URIs. It is not an error if @a uri is well-formed, but not defined in the ImageFile (the
|
||||
function just returns false).
|
||||
|
||||
@pre This ImageFile must be open (i.e. isOpen()).
|
||||
@pre uri != ""
|
||||
@post No visible state is modified.
|
||||
|
||||
@return true if URI is declared in the ImageFile.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsLookupPrefix
|
||||
*/
|
||||
bool ImageFile::extensionsLookupUri( const ustring &uri, ustring &prefix ) const
|
||||
{
|
||||
return impl_->extensionsLookupUri( uri, prefix );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get number of E57 extensions declared in the ImageFile.
|
||||
|
||||
@details
|
||||
The default E57 namespace does not count as an extension.
|
||||
|
||||
@pre This ImageFile must be open (i.e. isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The number of E57 extensions defined in the ImageFile.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsPrefix, ImageFile::extensionsUri
|
||||
*/
|
||||
size_t ImageFile::extensionsCount() const
|
||||
{
|
||||
return impl_->extensionsCount();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get an E57 extension prefix declared in an ImageFile by index.
|
||||
|
||||
@param [in] index The index of the prefix to get, starting at 0.
|
||||
|
||||
@details
|
||||
The order that the prefixes are stored in is not necessarily the same as the order they were
|
||||
created. However the prefix order will correspond to the URI order. The default E57 namespace is not
|
||||
counted as an extension.
|
||||
|
||||
@pre This ImageFile must be open (i.e. isOpen()).
|
||||
@pre 0 <= index < extensionsCount()
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The E57 extension prefix at the given index.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsCount, ImageFile::extensionsUri
|
||||
*/
|
||||
ustring ImageFile::extensionsPrefix( const size_t index ) const
|
||||
{
|
||||
return impl_->extensionsPrefix( index );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get an E57 extension URI declared in an ImageFile by index.
|
||||
|
||||
@param [in] index The index of the URI to get, starting at 0.
|
||||
|
||||
@details
|
||||
The order that the URIs are stored is not necessarily the same as the order they were created.
|
||||
However the URI order will correspond to the prefix order. The default E57 namespace is not counted
|
||||
as an extension.
|
||||
|
||||
@pre This ImageFile must be open (i.e. isOpen()).
|
||||
@pre 0 <= index < extensionsCount()
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The E57 extension URI at the given index.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsCount, ImageFile::extensionsPrefix
|
||||
*/
|
||||
ustring ImageFile::extensionsUri( const size_t index ) const
|
||||
{
|
||||
return impl_->extensionsUri( index );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Test whether an E57 element name has an extension prefix.
|
||||
|
||||
@details
|
||||
The element name has a prefix if the function elementNameParse(elementName,prefix,dummy) would
|
||||
succeed, and returned prefix != "".
|
||||
|
||||
@param [in] elementName The string element name to test.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return True if the E57 element name has an extension prefix.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
*/
|
||||
bool ImageFile::isElementNameExtended( const ustring &elementName ) const
|
||||
{
|
||||
return impl_->isElementNameExtended( elementName );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Parse element name into prefix and localPart substrings.
|
||||
|
||||
@param [in] elementName The string element name to parse into prefix and local parts.
|
||||
@param [out] prefix The prefix (if any) in the @a elementName.
|
||||
@param [out] localPart The part of the element name after the prefix.
|
||||
|
||||
@details
|
||||
A legal element name may be in prefixed (ID:ID) or unprefixed (ID) form, where ID is a string whose
|
||||
first character is in {a-z,A-Z,_} followed by zero or more characters in {a-z,A-Z,_,0-9,-,.}. If in
|
||||
prefixed form, the prefix does not have to be declared in the ImageFile.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::isElementNameExtended
|
||||
*/
|
||||
void ImageFile::elementNameParse( const ustring &elementName, ustring &prefix,
|
||||
ustring &localPart ) const
|
||||
{
|
||||
impl_->elementNameParse( elementName, prefix, localPart );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void ImageFile::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void ImageFile::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Test if two ImageFile handles refer to the same underlying ImageFile
|
||||
|
||||
@param [in] imf2 The ImageFile to compare this ImageFile with
|
||||
|
||||
@post No visible object state is modified.
|
||||
|
||||
@return @c true if ImageFile handles refer to the same underlying ImageFile.
|
||||
|
||||
@throw No E57Exceptions
|
||||
*/
|
||||
bool ImageFile::operator==( const ImageFile &imf2 ) const
|
||||
{
|
||||
return ( impl_ == imf2.impl_ );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Test if two ImageFile handles refer to different underlying ImageFile
|
||||
|
||||
@param [in] imf2 The ImageFile to compare this ImageFile with
|
||||
|
||||
@post No visible object state is modified.
|
||||
|
||||
@return @c true if ImageFile handles refer to different underlying ImageFiles.
|
||||
|
||||
@throw No E57Exceptions
|
||||
*/
|
||||
bool ImageFile::operator!=( const ImageFile &imf2 ) const
|
||||
{
|
||||
return ( impl_ != imf2.impl_ );
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
ImageFile::ImageFile( ImageFileImplSharedPtr imfi ) : impl_( imfi )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
602
src/3rdParty/libE57Format/src/ImageFileImpl.cpp
vendored
602
src/3rdParty/libE57Format/src/ImageFileImpl.cpp
vendored
@@ -26,9 +26,10 @@
|
||||
*/
|
||||
|
||||
#include "ImageFileImpl.h"
|
||||
#include "ASTMVersion.h"
|
||||
#include "CheckedFile.h"
|
||||
#include "E57Version.h"
|
||||
#include "E57XmlParser.h"
|
||||
#include "StringFunctions.h"
|
||||
#include "StructureNodeImpl.h"
|
||||
|
||||
namespace e57
|
||||
@@ -52,14 +53,13 @@ namespace e57
|
||||
uint64_t xmlPhysicalOffset = 0;
|
||||
uint64_t xmlLogicalLength = 0;
|
||||
uint64_t pageSize = 0;
|
||||
// char e57LibraryVersion[8]; //Not in V1.0 Standard
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void E57FileHeader::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
os << space( indent ) << "fileSignature: ";
|
||||
@@ -76,24 +76,24 @@ namespace e57
|
||||
|
||||
ImageFileImpl::ImageFileImpl( ReadChecksumPolicy policy ) :
|
||||
isWriter_( false ), writerCount_( 0 ), readerCount_( 0 ),
|
||||
checksumPolicy( std::max( 0, std::min( policy, 100 ) ) ), file_( nullptr ), xmlLogicalOffset_( 0 ),
|
||||
xmlLogicalLength_( 0 ), unusedLogicalStart_( 0 )
|
||||
checksumPolicy( std::max( 0, std::min( policy, 100 ) ) ), file_( nullptr ),
|
||||
xmlLogicalOffset_( 0 ), xmlLogicalLength_( 0 ), unusedLogicalStart_( 0 )
|
||||
{
|
||||
/// First phase of construction, can't do much until have the ImageFile
|
||||
/// object. See ImageFileImpl::construct2() for second phase.
|
||||
// First phase of construction, can't do much until have the ImageFile object. See
|
||||
// ImageFileImpl::construct2() for second phase.
|
||||
}
|
||||
|
||||
void ImageFileImpl::construct2( const ustring &fileName, const ustring &mode )
|
||||
{
|
||||
/// Second phase of construction, now we have a well-formed ImageFile object.
|
||||
// Second phase of construction, now we have a well-formed ImageFile object.
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "ImageFileImpl() called, fileName=" << fileName << " mode=" << mode << std::endl;
|
||||
#endif
|
||||
unusedLogicalStart_ = sizeof( E57FileHeader );
|
||||
fileName_ = fileName;
|
||||
|
||||
/// Get shared_ptr to this object
|
||||
// Get shared_ptr to this object
|
||||
ImageFileImplSharedPtr imf = shared_from_this();
|
||||
|
||||
// Accept "w" or "r" modes
|
||||
@@ -101,7 +101,7 @@ namespace e57
|
||||
|
||||
if ( !isWriter_ && ( mode != "r" ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT, "mode=" + ustring( mode ) );
|
||||
throw E57_EXCEPTION2( ErrorBadAPIArgument, "mode=" + ustring( mode ) );
|
||||
}
|
||||
|
||||
file_ = nullptr;
|
||||
@@ -111,8 +111,8 @@ namespace e57
|
||||
{
|
||||
try
|
||||
{
|
||||
/// Open file for writing, truncate if already exists.
|
||||
file_ = new CheckedFile( fileName_, CheckedFile::WriteCreate, checksumPolicy );
|
||||
// Open file for writing, truncate if already exists.
|
||||
file_ = new CheckedFile( fileName_, CheckedFile::Write, checksumPolicy );
|
||||
|
||||
std::shared_ptr<StructureNodeImpl> root( new StructureNodeImpl( imf ) );
|
||||
root_ = root;
|
||||
@@ -136,8 +136,8 @@ namespace e57
|
||||
// Reading
|
||||
try
|
||||
{
|
||||
/// Open file for reading.
|
||||
file_ = new CheckedFile( fileName_, CheckedFile::ReadOnly, checksumPolicy );
|
||||
// Open file for reading.
|
||||
file_ = new CheckedFile( fileName_, CheckedFile::Read, checksumPolicy );
|
||||
|
||||
std::shared_ptr<StructureNodeImpl> root( new StructureNodeImpl( imf ) );
|
||||
root_ = root;
|
||||
@@ -159,17 +159,17 @@ namespace e57
|
||||
|
||||
try
|
||||
{
|
||||
/// Create parser state, attach its event handers to the SAX2 reader
|
||||
// Create parser state, attach its event handers to the SAX2 reader
|
||||
E57XmlParser parser( imf );
|
||||
|
||||
parser.init();
|
||||
|
||||
/// Create input source (XML section of E57 file turned into a stream).
|
||||
// Create input source (XML section of E57 file turned into a stream).
|
||||
E57XmlFileInputSource xmlSection( file_, xmlLogicalOffset_, xmlLogicalLength_ );
|
||||
|
||||
unusedLogicalStart_ = sizeof( E57FileHeader );
|
||||
|
||||
/// Do the parse, building up the node tree
|
||||
// Do the parse, building up the node tree
|
||||
parser.parse( xmlSection );
|
||||
}
|
||||
catch ( ... )
|
||||
@@ -183,15 +183,15 @@ namespace e57
|
||||
|
||||
void ImageFileImpl::construct2( const char *input, const uint64_t size )
|
||||
{
|
||||
/// Second phase of construction, now we have a well-formed ImageFile object.
|
||||
// Second phase of construction, now we have a well-formed ImageFile object.
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "ImageFileImpl() called, fileName=<StreamBuffer> mode=r" << std::endl;
|
||||
#endif
|
||||
unusedLogicalStart_ = sizeof( E57FileHeader );
|
||||
fileName_ = "<StreamBuffer>";
|
||||
|
||||
/// Get shared_ptr to this object
|
||||
// Get shared_ptr to this object
|
||||
ImageFileImplSharedPtr imf = shared_from_this();
|
||||
|
||||
isWriter_ = false;
|
||||
@@ -199,7 +199,7 @@ namespace e57
|
||||
|
||||
try
|
||||
{
|
||||
/// Open file for reading.
|
||||
// Open file for reading.
|
||||
file_ = new CheckedFile( input, size, checksumPolicy );
|
||||
|
||||
std::shared_ptr<StructureNodeImpl> root( new StructureNodeImpl( imf ) );
|
||||
@@ -222,17 +222,17 @@ namespace e57
|
||||
|
||||
try
|
||||
{
|
||||
/// Create parser state, attach its event handers to the SAX2 reader
|
||||
// Create parser state, attach its event handers to the SAX2 reader
|
||||
E57XmlParser parser( imf );
|
||||
|
||||
parser.init();
|
||||
|
||||
/// Create input source (XML section of E57 file turned into a stream).
|
||||
// Create input source (XML section of E57 file turned into a stream).
|
||||
E57XmlFileInputSource xmlSection( file_, xmlLogicalOffset_, xmlLogicalLength_ );
|
||||
|
||||
unusedLogicalStart_ = sizeof( E57FileHeader );
|
||||
|
||||
/// Do the parse, building up the node tree
|
||||
// Do the parse, building up the node tree
|
||||
parser.parse( xmlSection );
|
||||
}
|
||||
catch ( ... )
|
||||
@@ -244,42 +244,6 @@ namespace e57
|
||||
}
|
||||
}
|
||||
|
||||
void ImageFileImpl::incrWriterCount()
|
||||
{
|
||||
writerCount_++;
|
||||
}
|
||||
|
||||
void ImageFileImpl::decrWriterCount()
|
||||
{
|
||||
writerCount_--;
|
||||
#ifdef E57_MAX_DEBUG
|
||||
if ( writerCount_ < 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "fileName=" + fileName_ +
|
||||
" writerCount=" + toString( writerCount_ ) +
|
||||
" readerCount=" + toString( readerCount_ ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImageFileImpl::incrReaderCount()
|
||||
{
|
||||
readerCount_++;
|
||||
}
|
||||
|
||||
void ImageFileImpl::decrReaderCount()
|
||||
{
|
||||
readerCount_--;
|
||||
#ifdef E57_MAX_DEBUG
|
||||
if ( readerCount_ < 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "fileName=" + fileName_ +
|
||||
" writerCount=" + toString( writerCount_ ) +
|
||||
" readerCount=" + toString( readerCount_ ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::shared_ptr<StructureNodeImpl> ImageFileImpl::root()
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
@@ -289,38 +253,33 @@ namespace e57
|
||||
|
||||
void ImageFileImpl::close()
|
||||
{
|
||||
/// If file already closed, have nothing to do
|
||||
if ( !file_ )
|
||||
// If file already closed, have nothing to do
|
||||
if ( file_ == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isWriter_ )
|
||||
{
|
||||
/// Go to end of file, note physical position
|
||||
// Go to end of file, note physical position
|
||||
xmlLogicalOffset_ = unusedLogicalStart_;
|
||||
file_->seek( xmlLogicalOffset_, CheckedFile::Logical );
|
||||
uint64_t xmlPhysicalOffset = file_->position( CheckedFile::Physical );
|
||||
*file_ << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
#ifdef E57_OXYGEN_SUPPORT /*//??? \
|
||||
//??? *file_ << "<?oxygen \
|
||||
// RNGSchema=\"file:/C:/kevin/astm/DataFormat/xif/las_v0_05.rnc\" \
|
||||
// type=\"compact\"?>\n";*/
|
||||
#endif
|
||||
|
||||
//??? need to add name space attributes to e57Root
|
||||
root_->writeXml( shared_from_this(), *file_, 0, "e57Root" );
|
||||
|
||||
/// Pad XML section so length is multiple of 4
|
||||
// Pad XML section so length is multiple of 4
|
||||
while ( ( file_->position( CheckedFile::Logical ) - xmlLogicalOffset_ ) % 4 != 0 )
|
||||
{
|
||||
*file_ << " ";
|
||||
}
|
||||
|
||||
/// Note logical length
|
||||
// Note logical length
|
||||
xmlLogicalLength_ = file_->position( CheckedFile::Logical ) - xmlLogicalOffset_;
|
||||
|
||||
/// Init header contents
|
||||
// Init header contents
|
||||
E57FileHeader header;
|
||||
|
||||
memcpy( &header.fileSignature, "ASTM-E57", 8 );
|
||||
@@ -331,11 +290,11 @@ namespace e57
|
||||
header.xmlPhysicalOffset = xmlPhysicalOffset;
|
||||
header.xmlLogicalLength = xmlLogicalLength_;
|
||||
header.pageSize = CheckedFile::physicalPageSize;
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
header.dump();
|
||||
#endif
|
||||
|
||||
/// Write header at beginning of file
|
||||
// Write header at beginning of file
|
||||
file_->seek( 0 );
|
||||
file_->write( reinterpret_cast<char *>( &header ), sizeof( header ) );
|
||||
|
||||
@@ -348,14 +307,14 @@ namespace e57
|
||||
|
||||
void ImageFileImpl::cancel()
|
||||
{
|
||||
/// If file already closed, have nothing to do
|
||||
if ( !file_ )
|
||||
// If file already closed, have nothing to do
|
||||
if ( file_ == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// Close the file and ulink (delete) it.
|
||||
/// It is legal to cancel a read file, but file isn't deleted.
|
||||
// Close the file and ulink (delete) it.
|
||||
// It is legal to cancel a read file, but file isn't deleted.
|
||||
if ( isWriter_ )
|
||||
{
|
||||
file_->unlink();
|
||||
@@ -391,9 +350,9 @@ namespace e57
|
||||
|
||||
ImageFileImpl::~ImageFileImpl()
|
||||
{
|
||||
/// Try to cancel if not already closed, but don't allow any exceptions to
|
||||
/// propagate to caller (because in dtor). If writing, this will unlink the
|
||||
/// file, so make sure call ImageFileImpl::close explicitly before dtor runs.
|
||||
// Try to cancel if not already closed, but don't allow any exceptions to propagate to caller
|
||||
// (because in dtor). If writing, this will unlink the file, so make sure call
|
||||
// ImageFileImpl::close explicitly before dtor runs.
|
||||
try
|
||||
{
|
||||
cancel();
|
||||
@@ -402,7 +361,7 @@ namespace e57
|
||||
{
|
||||
};
|
||||
|
||||
/// Just in case cancel failed without freeing file_, do free here.
|
||||
// Just in case cancel failed without freeing file_, do free here.
|
||||
delete file_;
|
||||
file_ = nullptr;
|
||||
}
|
||||
@@ -411,11 +370,11 @@ namespace e57
|
||||
{
|
||||
uint64_t oldLogicalStart = unusedLogicalStart_;
|
||||
|
||||
/// Reserve space at end of file
|
||||
// Reserve space at end of file
|
||||
unusedLogicalStart_ += byteCount;
|
||||
|
||||
/// If caller won't write to file immediately, it should request that the
|
||||
/// file be extended with zeros here
|
||||
// If caller won't write to file immediately, it should request that the file be extended with
|
||||
// zeros here.
|
||||
if ( doExtendNow )
|
||||
{
|
||||
file_->extend( unusedLogicalStart_ );
|
||||
@@ -441,21 +400,21 @@ namespace e57
|
||||
//??? check if prefix characters ok, check if uri has a double quote char
|
||||
//(others?)
|
||||
|
||||
/// Check to make sure that neither prefix or uri is already defined.
|
||||
// Check to make sure that neither prefix or uri is already defined.
|
||||
ustring dummy;
|
||||
|
||||
if ( extensionsLookupPrefix( prefix, dummy ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_DUPLICATE_NAMESPACE_PREFIX, "prefix=" + prefix + " uri=" + uri );
|
||||
throw E57_EXCEPTION2( ErrorDuplicateNamespacePrefix, "prefix=" + prefix + " uri=" + uri );
|
||||
}
|
||||
|
||||
if ( extensionsLookupUri( uri, dummy ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_DUPLICATE_NAMESPACE_URI, "prefix=" + prefix + " uri=" + uri );
|
||||
throw E57_EXCEPTION2( ErrorDuplicateNamespaceURI, "prefix=" + prefix + " uri=" + uri );
|
||||
;
|
||||
}
|
||||
|
||||
/// Append at end of list
|
||||
// Append at end of list
|
||||
nameSpaces_.emplace_back( prefix, uri );
|
||||
}
|
||||
|
||||
@@ -463,7 +422,7 @@ namespace e57
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
/// Linear search for matching prefix
|
||||
// Linear search for matching prefix
|
||||
std::vector<NameSpace>::const_iterator it;
|
||||
|
||||
for ( it = nameSpaces_.begin(); it < nameSpaces_.end(); ++it )
|
||||
@@ -482,7 +441,7 @@ namespace e57
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
/// Linear search for matching URI
|
||||
// Linear search for matching URI
|
||||
std::vector<NameSpace>::const_iterator it;
|
||||
|
||||
for ( it = nameSpaces_.begin(); it < nameSpaces_.end(); ++it )
|
||||
@@ -520,9 +479,9 @@ namespace e57
|
||||
|
||||
bool ImageFileImpl::isElementNameExtended( const ustring &elementName )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// Make sure doesn't have any "/" in it
|
||||
// Make sure doesn't have any "/" in it
|
||||
size_t found = elementName.find_first_of( '/' );
|
||||
|
||||
if ( found != std::string::npos )
|
||||
@@ -530,11 +489,12 @@ namespace e57
|
||||
return false;
|
||||
}
|
||||
|
||||
ustring prefix, localPart;
|
||||
ustring prefix;
|
||||
ustring localPart;
|
||||
|
||||
try
|
||||
{
|
||||
/// Throws if elementName bad
|
||||
// Throws if elementName bad
|
||||
elementNameParse( elementName, prefix, localPart );
|
||||
}
|
||||
catch ( E57Exception & /*ex*/ )
|
||||
@@ -542,13 +502,13 @@ namespace e57
|
||||
return false;
|
||||
}
|
||||
|
||||
/// If get here, the name was good, so test if found a prefix part
|
||||
// If get here, the name was good, so test if found a prefix part
|
||||
return ( prefix.length() > 0 );
|
||||
}
|
||||
|
||||
bool ImageFileImpl::isElementNameLegal( const ustring &elementName, bool allowNumber )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
// cout << "isElementNameLegal elementName=""" << elementName << """" <<
|
||||
// std::endl;
|
||||
#endif
|
||||
@@ -556,7 +516,7 @@ namespace e57
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
/// Throws if elementName bad
|
||||
// Throws if elementName bad
|
||||
checkElementNameLegal( elementName, allowNumber );
|
||||
}
|
||||
catch ( E57Exception & /*ex*/ )
|
||||
@@ -564,20 +524,20 @@ namespace e57
|
||||
return false;
|
||||
}
|
||||
|
||||
/// If get here, the name was good
|
||||
// If get here, the name was good
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImageFileImpl::isPathNameLegal( const ustring &pathName )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
// cout << "isPathNameLegal elementName=""" << pathName << """" << std::endl;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
/// Throws if pathName bad
|
||||
// Throws if pathName bad
|
||||
pathNameCheckWellFormed( pathName );
|
||||
}
|
||||
catch ( E57Exception & /*ex*/ )
|
||||
@@ -585,127 +545,45 @@ namespace e57
|
||||
return false;
|
||||
}
|
||||
|
||||
/// If get here, the name was good
|
||||
// If get here, the name was good
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImageFileImpl::checkElementNameLegal( const ustring &elementName, bool allowNumber )
|
||||
{
|
||||
/// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
|
||||
// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
|
||||
|
||||
ustring prefix;
|
||||
ustring localPart;
|
||||
|
||||
/// Throws if bad elementName
|
||||
// Throws if bad elementName
|
||||
elementNameParse( elementName, prefix, localPart, allowNumber );
|
||||
|
||||
/// If has prefix, it must be registered
|
||||
// If has prefix, it must be registered
|
||||
ustring uri;
|
||||
|
||||
if ( prefix.length() > 0 && !extensionsLookupPrefix( prefix, uri ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "elementName=" + elementName + " prefix=" + prefix );
|
||||
}
|
||||
}
|
||||
|
||||
void ImageFileImpl::elementNameParse( const ustring &elementName, ustring &prefix, ustring &localPart,
|
||||
bool allowNumber )
|
||||
{
|
||||
/// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
|
||||
|
||||
//??? check if elementName is good UTF-8?
|
||||
|
||||
size_t len = elementName.length();
|
||||
|
||||
/// Empty name is bad
|
||||
if ( len == 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "elementName=" + elementName );
|
||||
}
|
||||
|
||||
unsigned char c = elementName[0];
|
||||
|
||||
/// If allowing numeric element name, check if first char is digit
|
||||
if ( allowNumber && '0' <= c && c <= '9' )
|
||||
{
|
||||
/// All remaining characters must be digits
|
||||
for ( size_t i = 1; i < len; i++ )
|
||||
{
|
||||
c = elementName[i];
|
||||
|
||||
if ( !( '0' <= c && c <= '9' ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "elementName=" + elementName );
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// If first char is ASCII (< 128), check for legality
|
||||
/// Don't test any part of a multi-byte code point sequence (c >= 128).
|
||||
/// Don't allow ':' as first char.
|
||||
if ( c < 128 && !( ( 'a' <= c && c <= 'z' ) || ( 'A' <= c && c <= 'Z' ) || c == '_' ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "elementName=" + elementName );
|
||||
}
|
||||
|
||||
/// If each following char is ASCII (<128), check for legality
|
||||
/// Don't test any part of a multi-byte code point sequence (c >= 128).
|
||||
for ( size_t i = 1; i < len; i++ )
|
||||
{
|
||||
c = elementName[i];
|
||||
|
||||
if ( c < 128 && !( ( 'a' <= c && c <= 'z' ) || ( 'A' <= c && c <= 'Z' ) || c == '_' || c == ':' ||
|
||||
( '0' <= c && c <= '9' ) || c == '-' || c == '.' ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "elementName=" + elementName );
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if has at least one colon, try to split it into prefix & localPart
|
||||
size_t found = elementName.find_first_of( ':' );
|
||||
|
||||
if ( found != std::string::npos )
|
||||
{
|
||||
/// Check doesn't have two colons
|
||||
if ( elementName.find_first_of( ':', found + 1 ) != std::string::npos )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "elementName=" + elementName );
|
||||
}
|
||||
|
||||
/// Split element name at the colon
|
||||
/// ??? split before check first/subsequent char legal?
|
||||
prefix = elementName.substr( 0, found );
|
||||
localPart = elementName.substr( found + 1 );
|
||||
|
||||
if ( prefix.length() == 0 || localPart.length() == 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME,
|
||||
"elementName=" + elementName + " prefix=" + prefix + " localPart=" + localPart );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix = "";
|
||||
localPart = elementName;
|
||||
throw E57_EXCEPTION2( ErrorBadPathName,
|
||||
"elementName=" + elementName + " prefix=" + prefix );
|
||||
}
|
||||
}
|
||||
|
||||
void ImageFileImpl::pathNameCheckWellFormed( const ustring &pathName )
|
||||
{
|
||||
/// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
|
||||
// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
|
||||
|
||||
/// Just call pathNameParse() which throws if not well formed
|
||||
// Just call pathNameParse() which throws if not well formed
|
||||
bool isRelative = false;
|
||||
StringList fields;
|
||||
|
||||
pathNameParse( pathName, isRelative, fields );
|
||||
}
|
||||
|
||||
void ImageFileImpl::pathNameParse( const ustring &pathName, bool &isRelative, StringList &fields )
|
||||
void ImageFileImpl::pathNameParse( const ustring &pathName, bool &isRelative,
|
||||
StringList &fields )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "pathNameParse pathname="
|
||||
""
|
||||
<< pathName
|
||||
@@ -713,14 +591,14 @@ namespace e57
|
||||
""
|
||||
<< std::endl;
|
||||
#endif
|
||||
/// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
|
||||
// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
|
||||
|
||||
/// Clear previous contents of fields vector
|
||||
// Clear previous contents of fields vector
|
||||
fields.clear();
|
||||
|
||||
size_t start = 0;
|
||||
|
||||
/// Check if absolute path
|
||||
// Check if absolute path
|
||||
if ( pathName[start] == '/' )
|
||||
{
|
||||
isRelative = false;
|
||||
@@ -731,21 +609,24 @@ namespace e57
|
||||
isRelative = true;
|
||||
}
|
||||
|
||||
/// Save strings in between each forward slash '/'
|
||||
/// Don't ignore whitespace
|
||||
// Save strings in between each forward slash '/'
|
||||
// Don't ignore whitespace
|
||||
while ( start < pathName.size() )
|
||||
{
|
||||
size_t slash = pathName.find_first_of( '/', start );
|
||||
|
||||
/// Get element name from in between '/', check valid
|
||||
// Get element name from in between '/', check valid
|
||||
ustring elementName = pathName.substr( start, slash - start );
|
||||
|
||||
if ( !isElementNameLegal( elementName ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "pathName=" + pathName + " elementName=" + elementName );
|
||||
throw E57_EXCEPTION2( ErrorBadPathName, std::string( "pathName=" )
|
||||
.append( pathName )
|
||||
.append( " elementName=" )
|
||||
.append( elementName ) );
|
||||
}
|
||||
|
||||
/// Add to list
|
||||
// Add to list
|
||||
fields.push_back( elementName );
|
||||
|
||||
if ( slash == std::string::npos )
|
||||
@@ -753,35 +634,156 @@ namespace e57
|
||||
break;
|
||||
}
|
||||
|
||||
/// Handle case when pathname ends in /, e.g. "/foo/", add empty field at
|
||||
/// end of list
|
||||
// Handle case when pathname ends in /, e.g. "/foo/", add empty field at end of list
|
||||
if ( slash == pathName.size() - 1 )
|
||||
{
|
||||
fields.emplace_back( "" );
|
||||
break;
|
||||
}
|
||||
|
||||
/// Skip over the slash and keep going
|
||||
// Skip over the slash and keep going
|
||||
start = slash + 1;
|
||||
}
|
||||
|
||||
/// Empty relative path is not allowed
|
||||
// Empty relative path is not allowed
|
||||
if ( isRelative && fields.empty() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "pathName=" + pathName );
|
||||
throw E57_EXCEPTION2( ErrorBadPathName, "pathName=" + pathName );
|
||||
}
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << "pathNameParse returning: isRelative=" << isRelative << " fields.size()=" << fields.size()
|
||||
<< " fields=";
|
||||
for ( size_t i = 0; i < fields.size(); i++ )
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "pathNameParse returning: isRelative=" << isRelative
|
||||
<< " fields.size()=" << fields.size() << " fields=";
|
||||
for ( auto &field : fields )
|
||||
{
|
||||
std::cout << fields[i] << ",";
|
||||
std::cout << field << ",";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImageFileImpl::incrWriterCount()
|
||||
{
|
||||
writerCount_++;
|
||||
}
|
||||
|
||||
void ImageFileImpl::decrWriterCount()
|
||||
{
|
||||
writerCount_--;
|
||||
|
||||
#if ( E57_VALIDATION_LEVEL == VALIDATION_DEEP )
|
||||
if ( writerCount_ < 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorInternal, "fileName=" + fileName_ +
|
||||
" writerCount=" + toString( writerCount_ ) +
|
||||
" readerCount=" + toString( readerCount_ ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImageFileImpl::incrReaderCount()
|
||||
{
|
||||
readerCount_++;
|
||||
}
|
||||
|
||||
void ImageFileImpl::decrReaderCount()
|
||||
{
|
||||
readerCount_--;
|
||||
|
||||
#if ( E57_VALIDATION_LEVEL == VALIDATION_DEEP )
|
||||
if ( readerCount_ < 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorInternal, "fileName=" + fileName_ +
|
||||
" writerCount=" + toString( writerCount_ ) +
|
||||
" readerCount=" + toString( readerCount_ ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImageFileImpl::elementNameParse( const ustring &elementName, ustring &prefix,
|
||||
ustring &localPart, bool allowNumber )
|
||||
{
|
||||
// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
|
||||
|
||||
//??? check if elementName is good UTF-8?
|
||||
|
||||
size_t len = elementName.length();
|
||||
|
||||
// Empty name is bad
|
||||
if ( len == 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadPathName, "elementName=" + elementName );
|
||||
}
|
||||
|
||||
unsigned char c = elementName[0];
|
||||
|
||||
// If allowing numeric element name, check if first char is digit
|
||||
if ( allowNumber && '0' <= c && c <= '9' )
|
||||
{
|
||||
// All remaining characters must be digits
|
||||
for ( size_t i = 1; i < len; i++ )
|
||||
{
|
||||
c = elementName[i];
|
||||
|
||||
if ( c < '0' || c > '9' )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadPathName, "elementName=" + elementName );
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If first char is ASCII (< 128), check for legality
|
||||
// Don't test any part of a multi-byte code point sequence (c >= 128).
|
||||
// Don't allow ':' as first char.
|
||||
if ( c < 128 && !( ( 'a' <= c && c <= 'z' ) || ( 'A' <= c && c <= 'Z' ) || c == '_' ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadPathName, "elementName=" + elementName );
|
||||
}
|
||||
|
||||
// If each following char is ASCII (<128), check for legality
|
||||
// Don't test any part of a multi-byte code point sequence (c >= 128).
|
||||
for ( size_t i = 1; i < len; i++ )
|
||||
{
|
||||
c = elementName[i];
|
||||
|
||||
if ( c < 128 && !( ( 'a' <= c && c <= 'z' ) || ( 'A' <= c && c <= 'Z' ) || c == '_' ||
|
||||
c == ':' || ( '0' <= c && c <= '9' ) || c == '-' || c == '.' ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadPathName, "elementName=" + elementName );
|
||||
}
|
||||
}
|
||||
|
||||
// Check if has at least one colon, try to split it into prefix & localPart
|
||||
size_t found = elementName.find_first_of( ':' );
|
||||
|
||||
if ( found != std::string::npos )
|
||||
{
|
||||
// Check doesn't have two colons
|
||||
if ( elementName.find_first_of( ':', found + 1 ) != std::string::npos )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadPathName, "elementName=" + elementName );
|
||||
}
|
||||
|
||||
// Split element name at the colon
|
||||
// ??? split before check first/subsequent char legal?
|
||||
prefix = elementName.substr( 0, found );
|
||||
localPart = elementName.substr( found + 1 );
|
||||
|
||||
if ( prefix.length() == 0 || localPart.length() == 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadPathName, "elementName=" + elementName + " prefix=" +
|
||||
prefix + " localPart=" + localPart );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix = "";
|
||||
localPart = elementName;
|
||||
}
|
||||
}
|
||||
|
||||
ustring ImageFileImpl::pathNameUnparse( bool isRelative, const std::vector<ustring> &fields )
|
||||
{
|
||||
ustring path;
|
||||
@@ -804,96 +806,12 @@ namespace e57
|
||||
return path;
|
||||
}
|
||||
|
||||
void ImageFileImpl::readFileHeader( CheckedFile *file, E57FileHeader &header )
|
||||
{
|
||||
/// Double check that compiler thinks sizeof header is what it is supposed to
|
||||
/// be
|
||||
static_assert( sizeof( E57FileHeader ) == 48, "Unexpected size of E57FileHeader" );
|
||||
|
||||
/// Fetch the file header
|
||||
file->read( reinterpret_cast<char *>( &header ), sizeof( header ) );
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
header.dump();
|
||||
#endif
|
||||
|
||||
/// Check signature
|
||||
if ( strncmp( header.fileSignature, "ASTM-E57", 8 ) != 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_FILE_SIGNATURE, "fileName=" + file->fileName() );
|
||||
}
|
||||
|
||||
/// Check file version compatibility
|
||||
if ( header.majorVersion > E57_FORMAT_MAJOR )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_UNKNOWN_FILE_VERSION,
|
||||
"fileName=" + file->fileName() +
|
||||
" header.majorVersion=" + toString( header.majorVersion ) +
|
||||
" header.minorVersion=" + toString( header.minorVersion ) );
|
||||
}
|
||||
|
||||
/// If is a prototype version (majorVersion==0), then minorVersion has to
|
||||
/// match too. In production versions (majorVersion==E57_FORMAT_MAJOR),
|
||||
/// should be able to handle any minor version.
|
||||
if ( header.majorVersion == E57_FORMAT_MAJOR && header.minorVersion > E57_FORMAT_MINOR )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_UNKNOWN_FILE_VERSION,
|
||||
"fileName=" + file->fileName() +
|
||||
" header.majorVersion=" + toString( header.majorVersion ) +
|
||||
" header.minorVersion=" + toString( header.minorVersion ) );
|
||||
}
|
||||
|
||||
/// Check if file length matches actual physical length
|
||||
if ( header.filePhysicalLength != file->length( CheckedFile::Physical ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_FILE_LENGTH,
|
||||
"fileName=" + file->fileName() +
|
||||
" header.filePhysicalLength=" + toString( header.filePhysicalLength ) +
|
||||
" file->length=" + toString( file->length( CheckedFile::Physical ) ) );
|
||||
}
|
||||
|
||||
/// Check that page size is correct constant
|
||||
if ( header.majorVersion != 0 && header.pageSize != CheckedFile::physicalPageSize )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_FILE_LENGTH, "fileName=" + file->fileName() );
|
||||
}
|
||||
}
|
||||
|
||||
void ImageFileImpl::checkImageFileOpen( const char *srcFileName, int srcLineNumber,
|
||||
const char *srcFunctionName ) const
|
||||
{
|
||||
if ( !isOpen() )
|
||||
{
|
||||
throw E57Exception( E57_ERROR_IMAGEFILE_NOT_OPEN, "fileName=" + fileName(), srcFileName, srcLineNumber,
|
||||
srcFunctionName );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
void ImageFileImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
/// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
|
||||
os << space( indent ) << "fileName: " << fileName_ << std::endl;
|
||||
os << space( indent ) << "writerCount: " << writerCount_ << std::endl;
|
||||
os << space( indent ) << "readerCount: " << readerCount_ << std::endl;
|
||||
os << space( indent ) << "isWriter: " << isWriter_ << std::endl;
|
||||
for ( size_t i = 0; i < extensionsCount(); i++ )
|
||||
{
|
||||
os << space( indent ) << "nameSpace[" << i << "]: prefix=" << extensionsPrefix( i )
|
||||
<< " uri=" << extensionsUri( i ) << std::endl;
|
||||
}
|
||||
os << space( indent ) << "root: " << std::endl;
|
||||
root_->dump( indent + 2, os );
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned ImageFileImpl::bitsNeeded( int64_t minimum, int64_t maximum )
|
||||
{
|
||||
/// Relatively quick way to compute ceil(log2(maximum - minimum + 1)));
|
||||
/// Uses only integer operations and is machine independent (no assembly
|
||||
/// code). Find the bit position of the first 1 (from left) in the binary
|
||||
/// form of stateCountMinus1.
|
||||
///??? move to E57Utility?
|
||||
// Relatively quick way to compute ceil(log2(maximum - minimum + 1)));
|
||||
// Uses only integer operations and is machine independent (no assembly code). Find the bit
|
||||
// position of the first 1 (from left) in the binary form of stateCountMinus1.
|
||||
//??? move to E57Utility?
|
||||
|
||||
uint64_t stateCountMinus1 = maximum - minimum;
|
||||
|
||||
@@ -942,4 +860,86 @@ namespace e57
|
||||
|
||||
return log2;
|
||||
}
|
||||
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void ImageFileImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
|
||||
os << space( indent ) << "fileName: " << fileName_ << std::endl;
|
||||
os << space( indent ) << "writerCount: " << writerCount_ << std::endl;
|
||||
os << space( indent ) << "readerCount: " << readerCount_ << std::endl;
|
||||
os << space( indent ) << "isWriter: " << isWriter_ << std::endl;
|
||||
for ( size_t i = 0; i < extensionsCount(); i++ )
|
||||
{
|
||||
os << space( indent ) << "nameSpace[" << i << "]: prefix=" << extensionsPrefix( i )
|
||||
<< " uri=" << extensionsUri( i ) << std::endl;
|
||||
}
|
||||
os << space( indent ) << "root: " << std::endl;
|
||||
root_->dump( indent + 2, os );
|
||||
}
|
||||
#endif
|
||||
|
||||
void ImageFileImpl::readFileHeader( CheckedFile *file, E57FileHeader &header )
|
||||
{
|
||||
// Double check that compiler thinks sizeof header is what it is supposed to be
|
||||
static_assert( sizeof( E57FileHeader ) == 48, "Unexpected size of E57FileHeader" );
|
||||
|
||||
// Fetch the file header
|
||||
file->read( reinterpret_cast<char *>( &header ), sizeof( header ) );
|
||||
|
||||
#ifdef E57_VERBOSE
|
||||
header.dump();
|
||||
#endif
|
||||
|
||||
// Check signature
|
||||
if ( strncmp( header.fileSignature, "ASTM-E57", 8 ) != 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadFileSignature, "fileName=" + file->fileName() );
|
||||
}
|
||||
|
||||
// Check file version compatibility
|
||||
if ( header.majorVersion > E57_FORMAT_MAJOR )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorUnknownFileVersion,
|
||||
"fileName=" + file->fileName() +
|
||||
" header.majorVersion=" + toString( header.majorVersion ) +
|
||||
" header.minorVersion=" + toString( header.minorVersion ) );
|
||||
}
|
||||
|
||||
// If is a prototype version (majorVersion==0), then minorVersion has to match too. In
|
||||
// production versions (majorVersion==E57_FORMAT_MAJOR), should be able to handle any minor
|
||||
// version.
|
||||
if ( header.majorVersion == E57_FORMAT_MAJOR && header.minorVersion > E57_FORMAT_MINOR )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorUnknownFileVersion,
|
||||
"fileName=" + file->fileName() +
|
||||
" header.majorVersion=" + toString( header.majorVersion ) +
|
||||
" header.minorVersion=" + toString( header.minorVersion ) );
|
||||
}
|
||||
|
||||
// Check if file length matches actual physical length
|
||||
if ( header.filePhysicalLength != file->length( CheckedFile::Physical ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadFileLength,
|
||||
"fileName=" + file->fileName() + " header.filePhysicalLength=" +
|
||||
toString( header.filePhysicalLength ) + " file->length=" +
|
||||
toString( file->length( CheckedFile::Physical ) ) );
|
||||
}
|
||||
|
||||
// Check that page size is correct constant
|
||||
if ( header.majorVersion != 0 && header.pageSize != CheckedFile::physicalPageSize )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadFileLength, "fileName=" + file->fileName() );
|
||||
}
|
||||
}
|
||||
|
||||
void ImageFileImpl::checkImageFileOpen( const char *srcFileName, int srcLineNumber,
|
||||
const char *srcFunctionName ) const
|
||||
{
|
||||
if ( !isOpen() )
|
||||
{
|
||||
throw E57Exception( ErrorImageFileNotOpen, "fileName=" + fileName(), srcFileName,
|
||||
srcLineNumber, srcFunctionName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
src/3rdParty/libE57Format/src/ImageFileImpl.h
vendored
35
src/3rdParty/libE57Format/src/ImageFileImpl.h
vendored
@@ -41,10 +41,13 @@ namespace e57
|
||||
class ImageFileImpl : public std::enable_shared_from_this<ImageFileImpl>
|
||||
{
|
||||
public:
|
||||
ImageFileImpl( ReadChecksumPolicy policy );
|
||||
explicit ImageFileImpl( ReadChecksumPolicy policy );
|
||||
|
||||
void construct2( const ustring &fileName, const ustring &mode );
|
||||
void construct2( const char *input, const uint64_t size );
|
||||
void construct2( const char *input, uint64_t size );
|
||||
|
||||
std::shared_ptr<StructureNodeImpl> root();
|
||||
|
||||
void close();
|
||||
void cancel();
|
||||
bool isOpen() const;
|
||||
@@ -62,28 +65,31 @@ namespace e57
|
||||
bool extensionsLookupPrefix( const ustring &prefix, ustring &uri ) const;
|
||||
bool extensionsLookupUri( const ustring &uri, ustring &prefix ) const;
|
||||
size_t extensionsCount() const;
|
||||
ustring extensionsPrefix( const size_t index ) const;
|
||||
ustring extensionsUri( const size_t index ) const;
|
||||
ustring extensionsPrefix( size_t index ) const;
|
||||
ustring extensionsUri( size_t index ) const;
|
||||
|
||||
/// Utility functions:
|
||||
bool isElementNameExtended( const ustring &elementName );
|
||||
bool isElementNameLegal( const ustring &elementName, bool allowNumber = true );
|
||||
bool isPathNameLegal( const ustring &pathName );
|
||||
void checkElementNameLegal( const ustring &elementName, bool allowNumber = true );
|
||||
void elementNameParse( const ustring &elementName, ustring &prefix, ustring &localPart, bool allowNumber = true );
|
||||
|
||||
void pathNameCheckWellFormed( const ustring &pathName );
|
||||
void pathNameParse( const ustring &pathName, bool &isRelative, StringList &fields );
|
||||
ustring pathNameUnparse( bool isRelative, const StringList &fields );
|
||||
|
||||
unsigned bitsNeeded( int64_t minimum, int64_t maximum );
|
||||
void incrWriterCount();
|
||||
void decrWriterCount();
|
||||
void incrReaderCount();
|
||||
void decrReaderCount();
|
||||
|
||||
/// Diagnostic functions:
|
||||
#ifdef E57_DEBUG
|
||||
static void elementNameParse( const ustring &elementName, ustring &prefix, ustring &localPart,
|
||||
bool allowNumber = true );
|
||||
|
||||
static ustring pathNameUnparse( bool isRelative, const StringList &fields );
|
||||
|
||||
static unsigned bitsNeeded( int64_t minimum, int64_t maximum );
|
||||
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
|
||||
@@ -91,13 +97,12 @@ namespace e57
|
||||
friend class E57XmlParser;
|
||||
friend class BlobNodeImpl;
|
||||
friend class CompressedVectorWriterImpl;
|
||||
friend class CompressedVectorReaderImpl; //??? add file() instead of
|
||||
// accessing file_, others
|
||||
// friends too
|
||||
friend class CompressedVectorReaderImpl;
|
||||
|
||||
static void readFileHeader( CheckedFile *file, E57FileHeader &header );
|
||||
|
||||
void checkImageFileOpen( const char *srcFileName, int srcLineNumber, const char *srcFunctionName ) const;
|
||||
void checkImageFileOpen( const char *srcFileName, int srcLineNumber,
|
||||
const char *srcFunctionName ) const;
|
||||
|
||||
ustring fileName_;
|
||||
bool isWriter_;
|
||||
@@ -108,11 +113,11 @@ namespace e57
|
||||
|
||||
CheckedFile *file_;
|
||||
|
||||
/// Read file attributes
|
||||
// Read file attributes
|
||||
uint64_t xmlLogicalOffset_;
|
||||
uint64_t xmlLogicalLength_;
|
||||
|
||||
/// Write file attributes
|
||||
// Write file attributes
|
||||
uint64_t unusedLogicalStart_;
|
||||
|
||||
/// Bidirectional map from namespace prefix to uri
|
||||
|
||||
325
src/3rdParty/libE57Format/src/IntegerNode.cpp
vendored
Normal file
325
src/3rdParty/libE57Format/src/IntegerNode.cpp
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* IntegerNode.cpp - implementation of public functions of the IntegerNode class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file IntegerNode.cpp
|
||||
|
||||
#include "IntegerNodeImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether IntegerNode class invariant is true
|
||||
|
||||
@param [in] doRecurse If true, also check invariants of all children or sub-objects recursively.
|
||||
@param [in] doUpcast If true, also check invariants of the generic Node class.
|
||||
|
||||
@details
|
||||
This function checks at least the assertions in the documented class invariant description (see
|
||||
class reference page for this object). Other internal invariants that are implementation-dependent
|
||||
may also be checked. If any invariant clause is violated, an ::ErrorInvarianceViolation E57Exception
|
||||
is thrown.
|
||||
|
||||
Checking the invariant recursively may be expensive if the tree is large, so should be used
|
||||
judiciously, in debug versions of the application.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@throw ::ErrorInvarianceViolation or any other E57 ErrorCode
|
||||
*/
|
||||
void IntegerNode::checkInvariant( bool doRecurse, bool doUpcast ) const
|
||||
{
|
||||
E57_UNUSED( doRecurse );
|
||||
|
||||
// If destImageFile not open, can't test invariant (almost every call would throw)
|
||||
if ( !destImageFile().isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If requested, call Node::checkInvariant
|
||||
if ( doUpcast )
|
||||
{
|
||||
static_cast<Node>( *this ).checkInvariant( false, false );
|
||||
}
|
||||
|
||||
if ( value() < minimum() || value() > maximum() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::IntegerNode
|
||||
|
||||
@brief An E57 element encoding an integer value.
|
||||
|
||||
@details
|
||||
An IntegerNode is a terminal node (i.e. having no children) that holds an integer value, and
|
||||
minimum/maximum bounds. Once the IntegerNode value and attributes are set at creation, they may not
|
||||
be modified.
|
||||
|
||||
The minimum attribute may be a number in the interval [-2^63, 2^63).
|
||||
The maximum attribute may be a number in the interval [minimum, 2^63).
|
||||
The value may be a number in the interval [minimum, maximum].
|
||||
|
||||
See Node class discussion for discussion of the common functions that StructureNode supports.
|
||||
|
||||
@section IntegerNode_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude IntegerNode.cpp
|
||||
@skip void IntegerNode::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see Node, CompressedVector
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Create an E57 element for storing a integer value.
|
||||
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
@param [in] value The integer value of the element.
|
||||
@param [in] minimum The smallest value that the element may take.
|
||||
@param [in] maximum The largest value that the element may take.
|
||||
|
||||
@details
|
||||
An IntegerNode stores an integer value, and a lower and upper bound.
|
||||
The IntegerNode class corresponds to the ASTM E57 standard Integer element.
|
||||
See the class discussion at bottom of IntegerNode page for more details.
|
||||
|
||||
The @a destImageFile indicates which ImageFile the IntegerNode will eventually be attached to. A
|
||||
node is attached to an ImageFile by adding it underneath the predefined root of the ImageFile
|
||||
(gotten from ImageFile::root). It is not an error to fail to attach the IntegerNode to the @a
|
||||
destImageFile. It is an error to attempt to attach the IntegerNode to a different ImageFile.
|
||||
|
||||
@warning It is an error to give an @a value outside the @a minimum / @a maximum bounds, even if the
|
||||
IntegerNode is destined to be used in a CompressedVectorNode prototype (where the @a value will be
|
||||
ignored). If the IntegerNode is to be used in a prototype, it is recommended to specify a @a value =
|
||||
0 if 0 is within bounds, or a @a value = @a minimum if 0 is not within bounds.
|
||||
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
@pre minimum <= value <= maximum
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorValueOutOfBounds
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see IntegerNode::value, Node, CompressedVectorNode, CompressedVectorNode::prototype
|
||||
*/
|
||||
IntegerNode::IntegerNode( const ImageFile &destImageFile, int64_t value, int64_t minimum,
|
||||
int64_t maximum ) :
|
||||
impl_( new IntegerNodeImpl( destImageFile.impl(), value, minimum, maximum ) )
|
||||
{
|
||||
impl_->validateValue();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is this a root node.
|
||||
@copydetails Node::isRoot()
|
||||
*/
|
||||
bool IntegerNode::isRoot() const
|
||||
{
|
||||
return impl_->isRoot();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return parent of node, or self if a root node.
|
||||
@copydetails Node::parent()
|
||||
*/
|
||||
Node IntegerNode::parent() const
|
||||
{
|
||||
return Node( impl_->parent() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get absolute pathname of node.
|
||||
@copydetails Node::pathName()
|
||||
*/
|
||||
ustring IntegerNode::pathName() const
|
||||
{
|
||||
return impl_->pathName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get elementName string, that identifies the node in its parent.
|
||||
@copydetails Node::elementName()
|
||||
*/
|
||||
ustring IntegerNode::elementName() const
|
||||
{
|
||||
return impl_->elementName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the ImageFile that was declared as the destination for the node when it was created.
|
||||
@copydetails Node::destImageFile()
|
||||
*/
|
||||
ImageFile IntegerNode::destImageFile() const
|
||||
{
|
||||
return ImageFile( impl_->destImageFile() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Has node been attached into the tree of an ImageFile.
|
||||
@copydetails Node::isAttached()
|
||||
*/
|
||||
bool IntegerNode::isAttached() const
|
||||
{
|
||||
return impl_->isAttached();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get integer value stored.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return integer value stored.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see IntegerNode::minimum, IntegerNode::maximum
|
||||
*/
|
||||
int64_t IntegerNode::value() const
|
||||
{
|
||||
return impl_->value();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the declared minimum that the value may take.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The declared minimum that the value may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see IntegerNode::value
|
||||
*/
|
||||
int64_t IntegerNode::minimum() const
|
||||
{
|
||||
return impl_->minimum();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the declared maximum that the value may take.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The declared maximum that the value may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see IntegerNode::value
|
||||
*/
|
||||
int64_t IntegerNode::maximum() const
|
||||
{
|
||||
return impl_->maximum();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void IntegerNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void IntegerNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Upcast a IntegerNode handle to a generic Node handle.
|
||||
|
||||
@details
|
||||
An upcast is always safe, and the compiler can automatically insert it for initializations of Node
|
||||
variables and Node function arguments.
|
||||
|
||||
@return A smart Node handle referencing the underlying object.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see explanation in Node, Node::type(), IntegerNode(const Node&)
|
||||
*/
|
||||
IntegerNode::operator Node() const
|
||||
{
|
||||
// Upcast from shared_ptr<IntegerNodeImpl> to SharedNodeImplPtr and construct a Node object
|
||||
return Node( impl_ );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Downcast a generic Node handle to a IntegerNode handle.
|
||||
|
||||
@param [in] n The generic handle to downcast.
|
||||
|
||||
@details
|
||||
The handle @a n must be for an underlying IntegerNode, otherwise an exception is thrown. In designs
|
||||
that need to avoid the exception, use Node::type() to determine the actual type of the @a n before
|
||||
downcasting. This function must be explicitly called (c++ compiler cannot insert it automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
|
||||
@see Node::type(), IntegerNode::operator Node()
|
||||
*/
|
||||
IntegerNode::IntegerNode( const Node &n )
|
||||
{
|
||||
if ( n.type() != TypeInteger )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadNodeDowncast, "nodeType=" + toString( n.type() ) );
|
||||
}
|
||||
|
||||
// Set our shared_ptr to the downcast shared_ptr
|
||||
impl_ = std::static_pointer_cast<IntegerNodeImpl>( n.impl() );
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
IntegerNode::IntegerNode( std::shared_ptr<IntegerNodeImpl> ni ) : impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
@@ -27,22 +27,25 @@
|
||||
|
||||
#include "IntegerNodeImpl.h"
|
||||
#include "CheckedFile.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
IntegerNodeImpl::IntegerNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t value, int64_t minimum,
|
||||
int64_t maximum ) :
|
||||
NodeImpl( destImageFile ),
|
||||
value_( value ), minimum_( minimum ), maximum_( maximum )
|
||||
IntegerNodeImpl::IntegerNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t value,
|
||||
int64_t minimum, int64_t maximum ) :
|
||||
NodeImpl( destImageFile ), value_( value ), minimum_( minimum ), maximum_( maximum )
|
||||
{
|
||||
// don't checkImageFileOpen, NodeImpl() will do it
|
||||
}
|
||||
|
||||
/// Enforce the given bounds
|
||||
if ( value < minimum || maximum < value )
|
||||
// Throw an exception if the value is not within bounds.
|
||||
void IntegerNodeImpl::validateValue() const
|
||||
{
|
||||
if ( value_ < minimum_ || value_ > maximum_ )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_VALUE_OUT_OF_BOUNDS,
|
||||
"this->pathName=" + this->pathName() + " value=" + toString( value ) +
|
||||
" minimum=" + toString( minimum ) + " maximum=" + toString( maximum ) );
|
||||
throw E57_EXCEPTION2( ErrorValueOutOfBounds, "this->pathName=" + this->pathName() +
|
||||
" value=" + toString( value_ ) +
|
||||
" minimum=" + toString( minimum_ ) +
|
||||
" maximum=" + toString( maximum_ ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,30 +53,30 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// Same node type?
|
||||
if ( ni->type() != E57_INTEGER )
|
||||
// Same node type?
|
||||
if ( ni->type() != TypeInteger )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// Downcast to shared_ptr<IntegerNodeImpl>
|
||||
// Downcast to shared_ptr<IntegerNodeImpl>
|
||||
std::shared_ptr<IntegerNodeImpl> ii( std::static_pointer_cast<IntegerNodeImpl>( ni ) );
|
||||
|
||||
/// minimum must match
|
||||
// minimum must match
|
||||
if ( minimum_ != ii->minimum_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// maximum must match
|
||||
// maximum must match
|
||||
if ( maximum_ != ii->maximum_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// ignore value_, doesn't have to match
|
||||
// ignore value_, doesn't have to match
|
||||
|
||||
/// Types match
|
||||
// Types match
|
||||
return ( true );
|
||||
}
|
||||
|
||||
@@ -81,7 +84,7 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// We have no sub-structure, so if path not empty return false
|
||||
// We have no sub-structure, so if path not empty return false
|
||||
return pathName.empty();
|
||||
}
|
||||
|
||||
@@ -107,10 +110,10 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// We are a leaf node, so verify that we are listed in set.
|
||||
// We are a leaf node, so verify that we are listed in set.
|
||||
if ( pathNames.find( relativePathName( origin ) ) == pathNames.end() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_NO_BUFFER_FOR_ELEMENT, "this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorNoBufferForElement, "this->pathName=" + this->pathName() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +123,7 @@ namespace e57
|
||||
// don't checkImageFileOpen
|
||||
|
||||
ustring fieldName;
|
||||
if ( forcedFieldName )
|
||||
if ( forcedFieldName != nullptr )
|
||||
{
|
||||
fieldName = forcedFieldName;
|
||||
}
|
||||
@@ -131,17 +134,17 @@ namespace e57
|
||||
|
||||
cf << space( indent ) << "<" << fieldName << " type=\"Integer\"";
|
||||
|
||||
/// Don't need to write if are default values
|
||||
if ( minimum_ != E57_INT64_MIN )
|
||||
// Don't need to write if are default values
|
||||
if ( minimum_ != INT64_MIN )
|
||||
{
|
||||
cf << " minimum=\"" << minimum_ << "\"";
|
||||
}
|
||||
if ( maximum_ != E57_INT64_MAX )
|
||||
if ( maximum_ != INT64_MAX )
|
||||
{
|
||||
cf << " maximum=\"" << maximum_ << "\"";
|
||||
}
|
||||
|
||||
/// Write value as child text, unless it is the default value
|
||||
// Write value as child text, unless it is the default value
|
||||
if ( value_ != 0 )
|
||||
{
|
||||
cf << ">" << value_ << "</" << fieldName << ">\n";
|
||||
@@ -152,12 +155,11 @@ namespace e57
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void IntegerNodeImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
os << space( indent ) << "type: Integer"
|
||||
<< " (" << type() << ")" << std::endl;
|
||||
os << space( indent ) << "type: Integer" << " (" << type() << ")" << std::endl;
|
||||
NodeImpl::dump( indent, os );
|
||||
os << space( indent ) << "value: " << value_ << std::endl;
|
||||
os << space( indent ) << "minimum: " << minimum_ << std::endl;
|
||||
|
||||
11
src/3rdParty/libE57Format/src/IntegerNodeImpl.h
vendored
11
src/3rdParty/libE57Format/src/IntegerNodeImpl.h
vendored
@@ -33,14 +33,17 @@ namespace e57
|
||||
class IntegerNodeImpl : public NodeImpl
|
||||
{
|
||||
public:
|
||||
IntegerNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t value = 0, int64_t minimum = 0,
|
||||
int64_t maximum = 0 );
|
||||
IntegerNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t value, int64_t minimum,
|
||||
int64_t maximum );
|
||||
~IntegerNodeImpl() override = default;
|
||||
|
||||
NodeType type() const override
|
||||
{
|
||||
return E57_INTEGER;
|
||||
return TypeInteger;
|
||||
}
|
||||
|
||||
void validateValue() const;
|
||||
|
||||
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
|
||||
bool isDefined( const ustring &pathName ) override;
|
||||
|
||||
@@ -53,7 +56,7 @@ namespace e57
|
||||
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
|
||||
const char *forcedFieldName = nullptr ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
|
||||
604
src/3rdParty/libE57Format/src/Node.cpp
vendored
Normal file
604
src/3rdParty/libE57Format/src/Node.cpp
vendored
Normal file
@@ -0,0 +1,604 @@
|
||||
/*
|
||||
* Node.cpp - implementation of public functions of the Node class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file Node.cpp
|
||||
|
||||
#include "NodeImpl.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether Node class invariant is true
|
||||
|
||||
@param [in] doRecurse If true, also check invariants of all children or sub-objects recursively.
|
||||
@param [in] doDowncast If true, also check any invariants of the actual derived type in addition to
|
||||
the generic node invariants.
|
||||
|
||||
@details
|
||||
This function checks at least the assertions in the documented class invariant description (see
|
||||
class reference page for this object). Other internal invariants that are implementation-dependent
|
||||
may also be checked. If any invariant clause is violated, an E57Exception with errorCode of
|
||||
ErrorInvarianceViolation is thrown.
|
||||
|
||||
Specifying doRecurse=true only makes sense if doDowncast=true is also specified (the generic Node
|
||||
has no way to access any children). Checking the invariant recursively may be expensive if the tree
|
||||
is large, so should be used judiciously, in debug versions of the application.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@throw ::ErrorInvarianceViolation or any other E57 ErrorCode
|
||||
|
||||
@see Class Invariant section in Node, IntegerNode::checkInvariant,
|
||||
ScaledIntegerNode::checkInvariant, FloatNode::checkInvariant, BlobNode::checkInvariant,
|
||||
StructureNode::checkInvariant, VectorNode::checkInvariant, CompressedVectorNode::checkInvariant
|
||||
*/
|
||||
void Node::checkInvariant( bool doRecurse, bool doDowncast )
|
||||
{
|
||||
ImageFile imf = destImageFile();
|
||||
|
||||
// If destImageFile not open, can't test invariant (almost every call would throw)
|
||||
if ( !imf.isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Parent attachment state is same as this attachment state
|
||||
if ( isAttached() != parent().isAttached() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Parent destination ImageFile is same as this
|
||||
if ( imf != parent().destImageFile() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// If this is the ImageFile root node
|
||||
if ( *this == imf.root() )
|
||||
{
|
||||
// Must be attached
|
||||
if ( !isAttached() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Must be is a root node
|
||||
if ( !isRoot() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a root node
|
||||
if ( isRoot() )
|
||||
{
|
||||
// Absolute pathName is "/"
|
||||
if ( pathName() != "/" )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// parent() returns this node
|
||||
if ( *this != parent() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-root can't be own parent
|
||||
if ( *this == parent() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// pathName is concatenation of parent pathName and this elementName
|
||||
if ( parent().isRoot() )
|
||||
{
|
||||
if ( pathName() != "/" + elementName() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pathName() != parent().pathName() + "/" + elementName() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
// Non-root nodes must be children of either a VectorNode or StructureNode
|
||||
if ( parent().type() == TypeVector )
|
||||
{
|
||||
VectorNode v = static_cast<VectorNode>( parent() );
|
||||
|
||||
// Must be defined in parent VectorNode with this elementName
|
||||
if ( !v.isDefined( elementName() ) )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Getting child of parent with this elementName must return this
|
||||
if ( v.get( elementName() ) != *this )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
else if ( parent().type() == TypeStructure )
|
||||
{
|
||||
StructureNode s = static_cast<StructureNode>( parent() );
|
||||
|
||||
// Must be defined in parent VectorNode with this elementName
|
||||
if ( !s.isDefined( elementName() ) )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Getting child of parent with this elementName must return this
|
||||
if ( s.get( elementName() ) != *this )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
// If this is attached
|
||||
if ( isAttached() )
|
||||
{
|
||||
// Get root of this
|
||||
Node n = *this;
|
||||
while ( !n.isRoot() )
|
||||
{
|
||||
n = n.parent();
|
||||
}
|
||||
|
||||
// If in tree of ImageFile (could be in a prototype instead)
|
||||
if ( n == imf.root() )
|
||||
{
|
||||
// pathName must be defined
|
||||
if ( !imf.root().isDefined( pathName() ) )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Getting by absolute pathName must be this
|
||||
if ( imf.root().get( pathName() ) != *this )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If requested, check invariants of derived types:
|
||||
if ( doDowncast )
|
||||
{
|
||||
switch ( type() )
|
||||
{
|
||||
case TypeStructure:
|
||||
{
|
||||
StructureNode s( *this );
|
||||
s.checkInvariant( doRecurse, false );
|
||||
}
|
||||
break;
|
||||
case TypeVector:
|
||||
{
|
||||
VectorNode v( *this );
|
||||
v.checkInvariant( doRecurse, false );
|
||||
}
|
||||
break;
|
||||
case TypeCompressedVector:
|
||||
{
|
||||
CompressedVectorNode cv( *this );
|
||||
cv.checkInvariant( doRecurse, false );
|
||||
}
|
||||
break;
|
||||
case TypeInteger:
|
||||
{
|
||||
IntegerNode i( *this );
|
||||
i.checkInvariant( doRecurse, false );
|
||||
}
|
||||
break;
|
||||
case TypeScaledInteger:
|
||||
{
|
||||
ScaledIntegerNode si( *this );
|
||||
si.checkInvariant( doRecurse, false );
|
||||
}
|
||||
break;
|
||||
case TypeFloat:
|
||||
{
|
||||
FloatNode f( *this );
|
||||
f.checkInvariant( doRecurse, false );
|
||||
}
|
||||
break;
|
||||
case TypeString:
|
||||
{
|
||||
StringNode s( *this );
|
||||
s.checkInvariant( doRecurse, false );
|
||||
}
|
||||
break;
|
||||
case TypeBlob:
|
||||
{
|
||||
BlobNode b( *this );
|
||||
b.checkInvariant( doRecurse, false );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::Node
|
||||
|
||||
@brief Generic handle to any of the 8 types of E57 element objects.
|
||||
|
||||
@details
|
||||
A Node is a generic handle to an underlying object that is any of the eight type of E57 element
|
||||
objects. Each of the eight node types support the all the functions of the Node class. A Node is a
|
||||
vertex in a tree (acyclic graph), which is a hierarchical organization of nodes. At the top of the
|
||||
hierarchy is a single root Node. If a Node is a container type (StructureNode, VectorNode,
|
||||
CompressedVectorNode) it may have child nodes. The following are non-container type nodes (also
|
||||
known as terminal nodes): IntegerNode, ScaledIntegerNode, FloatNode, StringNode, BlobNode. Terminal
|
||||
nodes store various types of values and cannot have children. Each Node has an elementName, which is
|
||||
a string that uniquely identifies it within the children of its parent. Children of a StructureNode
|
||||
have elementNames that are explicitly given by the API user. Children of a VectorNode or
|
||||
CompressedVectorNode have element names that are string reorientations of the Node's positional
|
||||
index, starting at "0". A path name is a sequence elementNames (divided by "/") that must be
|
||||
traversed to get from a Node to one of its descendents.
|
||||
|
||||
Data is organized in an E57 format file (an ImageFile) hierarchically. Each ImageFile has a
|
||||
predefined root node that other nodes can be attached to as children (either directly or
|
||||
indirectly). A Node can exist temporarily without being attached to an ImageFile, however the state
|
||||
will not be saved in the associated file, and the state will be lost if the program exits.
|
||||
|
||||
A handle to a generic Node may be safely be converted to and from a handle to the Node's true
|
||||
underlying type. Since an attempt to convert a generic Node to a incorrect handle type will fail
|
||||
with an exception, the true type should be interrogated beforehand.
|
||||
|
||||
Due to the set-once design of the Foundation API, terminal nodes are immutable (i.e. their values
|
||||
and attributes can't change after creation). Once a parent-child relationship has been established,
|
||||
it cannot be changed.
|
||||
|
||||
Only generic operations are available for a Node, to access more specific operations (e.g.
|
||||
StructureNode::childCount) the generic handle must be converted to the node type of the underlying
|
||||
object. This conversion is done in a type-safe way using "downcasting" (see discussion below).
|
||||
|
||||
@section node_Downcasting Downcasting
|
||||
The conversion from a general handle type to a specific handle type is called "downcasting". Each of
|
||||
the 8 specific node types have a downcast function (see IntegerNode::IntegerNode(const Node&) for
|
||||
example). If a downcast is requested to an incorrect type (e.g. taking a Node handle that is
|
||||
actually a FloatNode and trying to downcast it to a IntegerNode), an E57Exception is thrown with an
|
||||
ErrorCode of ::ErrorBadNodeDowncast. Depending on the program design, throwing a bad downcast
|
||||
exception might be acceptable, if an element must be a specific type and no recovery is possible. If
|
||||
a standard requires an element be one several types, then Node::type() should be used to interrogate
|
||||
the type in an @c if or @c switch statement. Downcasting is "dangerous" (can fail with an exception)
|
||||
so the API requires the programmer to explicitly call the downcast functions rather than have the
|
||||
c++ compiler insert them automatically.
|
||||
|
||||
@section node_Upcasting Upcasting
|
||||
The conversion of a specific node handle (e.g. IntegerNode) to a general Node handle is called
|
||||
"upcasting". Each of the 8 specific node types have an upcast function (see IntegerNode::operator
|
||||
Node() for example). Upcasting is "safe" (can't cause an exception) so the API allows the c++
|
||||
compiler to insert them automatically. Upcasting is useful if you have a specific node handle and
|
||||
want to call a function that takes a generic Node handle argument. In this case, the function can be
|
||||
called with the specific handle and the compiler will automatically insert the upcast conversion.
|
||||
This implicit conversion allows one function, with an argument of type Node, to handle operations
|
||||
that apply to all 8 types of nodes (e.g. StructureNode::set()).
|
||||
|
||||
@section node_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude Node.cpp
|
||||
@skip void Node::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see StructureNode, VectorNode, CompressedVectorNode, IntegerNode, ScaledIntegerNode, FloatNode,
|
||||
StringNode, BlobNode
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Return the NodeType of a generic Node.
|
||||
|
||||
@details
|
||||
This function allows the actual node type to be interrogated before upcasting the handle to the
|
||||
actual node type (see Upcasting and Downcasting section in Node).
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The NodeType of a generic Node, which may be one of the following NodeType enumeration
|
||||
values:
|
||||
::TypeStructure, ::TypeVector, ::TypeCompressedVector, ::TypeInteger, ::TypeScaledInteger,
|
||||
::TypeFloat, ::TypeString, ::TypeBlob.
|
||||
|
||||
@see NodeType, upcast/downcast discussion in Node
|
||||
*/
|
||||
NodeType Node::type() const
|
||||
{
|
||||
return impl_->type();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is this a root node.
|
||||
|
||||
@details
|
||||
A root node has itself as a parent (it is not a child of any node).
|
||||
Newly constructed nodes (before they are inserted into an ImageFile tree) start out as root nodes.
|
||||
It is possible to temporarily create small trees that are unattached to any ImageFile. In these
|
||||
temporary trees, the top-most node will be a root node. After the tree is attached to the ImageFile
|
||||
tree, the only root node will be the pre-created one of the ImageTree (the one returned by
|
||||
ImageFile::root). The concept of @em attachment is slightly larger than that of the parent-child
|
||||
relationship (see Node::isAttached and CompressedVectorNode::CompressedVectorNode for more details).
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return true if this node is a root node.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node::parent, Node::isAttached, CompressedVectorNode::CompressedVectorNode
|
||||
*/
|
||||
bool Node::isRoot() const
|
||||
{
|
||||
return impl_->isRoot();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return parent of node, or self if a root node.
|
||||
|
||||
@details
|
||||
Nodes are organized into trees (acyclic graphs) with a distinguished node (the "top-most" node)
|
||||
called the root node. A parent-child relationship is established between nodes to form a tree. Nodes
|
||||
can have zero or one parent. Nodes with zero parents are called root nodes.
|
||||
|
||||
In the API, if a node has zero parents it is represented by having itself as a parent. Due to the
|
||||
set-once design of the API, a parent-child relationship cannot be modified once established. A child
|
||||
node can be any of the 8 node types, but a parent node can only be one of the 3 container node types
|
||||
(::TypeStructure, ::TypeVector, and ::TypeCompressedVector). Each parent-child link has a string
|
||||
name (the elementName) associated with it (See Node::elementName for more details). More than one
|
||||
tree can be formed at any given time. Typically small trees are temporarily constructed before
|
||||
attachment to an ImageFile so that they will be written to the disk.
|
||||
|
||||
@warning User algorithms that use this function to walk the tree must take care to handle the case
|
||||
where a node is its own parent (it is a root node). Use Node::isRoot to avoid infinite loops or
|
||||
infinite recursion.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return A smart Node handle referencing the parent node or this node if is a root node.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node::isRoot, Node::isAttached, CompressedVectorNode::CompressedVectorNode, Node::elementName
|
||||
*/
|
||||
Node Node::parent() const
|
||||
{
|
||||
return Node( impl_->parent() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get absolute pathname of node.
|
||||
|
||||
@details
|
||||
Nodes are organized into trees (acyclic graphs) by a parent-child relationship between nodes. Each
|
||||
parent-child relationship has an associated elementName string that is unique for a given parent.
|
||||
Any node in a given tree can be identified by a sequence of elementNames of how to get to the node
|
||||
from the root of the tree. An absolute pathname string that is formed by arranging this sequence of
|
||||
elementNames separated by the "/" character with a leading "/" prepended.
|
||||
|
||||
Some example absolute pathNames: "/data3D/0/points/153/cartesianX", "/data3D/0/points",
|
||||
"/cameraImages/1/pose/rotation/w", and "/". These examples have probably been attached to an
|
||||
ImageFile. Here is an example absolute pathName of a node in a pose tree that has not yet been
|
||||
attached to an ImageFile: "/pose/rotation/w".
|
||||
|
||||
A technical aside: the elementName of a root node does not appear in absolute pathnames, since the
|
||||
"path" is between the staring node (the root) and the ending node. By convention, in this API, a
|
||||
root node has the empty string ("") as its elementName.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The absolute path name of the node.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node::elementName, Node::parent, Node::isRoot
|
||||
*/
|
||||
ustring Node::pathName() const
|
||||
{
|
||||
return impl_->pathName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get element name of node.
|
||||
|
||||
@details
|
||||
The elementName is a string associated with each parent-child link between nodes. For a given
|
||||
parent, the elementName uniquely identifies each of its children. Thus, any node in a tree can be
|
||||
identified by a sequence of elementNames that form a path from the tree's root node (see
|
||||
Node::pathName for more details).
|
||||
|
||||
Three types of nodes (the container node types) can be parents: StructureNode, VectorNode, and
|
||||
CompressedVectorNode. The children of a StructureNode are explicitly given unique elementNames when
|
||||
they are attached to the parent (using StructureNode::set). The children of VectorNode and
|
||||
CompressedVectorNode are implicitly given elementNames based on their position in the list (starting
|
||||
at "0"). In a CompressedVectorNode, the elementName can become quite large: "1000000000" or more.
|
||||
However in a CompressedVectorNode, the elementName string is not stored in the file and is deduced
|
||||
by the position of the child.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The element name of the node, or "" if a root node.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node::pathName, Node::parent, Node::isRoot
|
||||
*/
|
||||
ustring Node::elementName() const
|
||||
{
|
||||
return impl_->elementName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the ImageFile that was declared as the destination for the node when it was created.
|
||||
|
||||
@details
|
||||
The first argument of the constructors of each of the 8 types of nodes is an ImageFile that
|
||||
indicates which ImageFile the node will eventually be attached to. This function returns that
|
||||
constructor argument. It is an error to attempt to attach the node to a different ImageFile. However
|
||||
it is not an error to not attach the node to any ImageFile (it's just wasteful). Use
|
||||
Node::isAttached to check if the node actually did get attached.
|
||||
|
||||
@post No visible object state is modified.
|
||||
|
||||
@return The ImageFile that was declared as the destination for the node when it was created.
|
||||
|
||||
@see Node::isAttached, StructureNode::StructureNode(), VectorNode::VectorNode(),
|
||||
CompressedVectorNode::CompressedVectorNode(), IntegerNode::IntegerNode(),
|
||||
ScaledIntegerNode::ScaledIntegerNode(), FloatNode::FloatNode(), StringNode::StringNode(),
|
||||
BlobNode::BlobNode()
|
||||
*/
|
||||
ImageFile Node::destImageFile() const
|
||||
{
|
||||
return ImageFile( impl_->destImageFile() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Has node been attached into the tree of an ImageFile.
|
||||
|
||||
@details
|
||||
Nodes are attached into an ImageFile tree by inserting them as children (directly or indirectly) of
|
||||
the ImageFile's root node. Nodes can also be attached to an ImageFile if they are used in the @c
|
||||
codecs or @c prototype trees of an CompressedVectorNode that is attached. Attached nodes will be
|
||||
saved to disk when the ImageFile is closed, and restored when the ImageFile is read back in from
|
||||
disk. Unattached nodes will not be saved to disk. It is not recommended to create nodes that are not
|
||||
eventually attached to the ImageFile.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible object state is modified.
|
||||
|
||||
@return @c true if node is child of (or in codecs or prototype of a child CompressedVectorNode of)
|
||||
the root node of an ImageFile.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node::destImageFile, ImageFile::root
|
||||
*/
|
||||
bool Node::isAttached() const
|
||||
{
|
||||
return impl_->isAttached();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
|
||||
@param [in] indent Number of spaces to indent all the printed lines of this object.
|
||||
@param [in] os Output stream to print on.
|
||||
|
||||
@details
|
||||
All objects in the E57 Foundation API (with exception of E57Exception) support a dump() function.
|
||||
These functions print out to the console a detailed listing of the internal state of objects. The
|
||||
content of these printouts is not documented, and is really of interest only to implementation
|
||||
developers/maintainers or the really adventurous users. In implementations of the API other than the
|
||||
Reference Implementation, the dump() functions may produce no output (although the functions should
|
||||
still be defined). The output format may change from version to version.
|
||||
|
||||
@post No visible object state is modified.
|
||||
|
||||
@throw No E57Exceptions
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void Node::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void Node::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Test if two node handles refer to the same underlying node
|
||||
|
||||
@param [in] n2 The node to compare this node with
|
||||
|
||||
@post No visible object state is modified.
|
||||
|
||||
@return @c true if node handles refer to the same underlying node.
|
||||
|
||||
@throw No E57Exceptions
|
||||
*/
|
||||
bool Node::operator==( const Node &n2 ) const
|
||||
{
|
||||
return ( impl_ == n2.impl_ );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Test if two node handles refer to different underlying nodes
|
||||
|
||||
@param [in] n2 The node to compare this node with
|
||||
|
||||
@post No visible object state is modified.
|
||||
|
||||
@return @c true if node handles refer to different underlying nodes.
|
||||
|
||||
@throw No E57Exceptions
|
||||
*/
|
||||
bool Node::operator!=( const Node &n2 ) const
|
||||
{
|
||||
return ( impl_ != n2.impl_ );
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
Node::Node( NodeImplSharedPtr ni ) : impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
202
src/3rdParty/libE57Format/src/NodeImpl.cpp
vendored
202
src/3rdParty/libE57Format/src/NodeImpl.cpp
vendored
@@ -28,24 +28,28 @@
|
||||
#include "NodeImpl.h"
|
||||
#include "ImageFileImpl.h"
|
||||
#include "SourceDestBufferImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
#include "VectorNodeImpl.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
NodeImpl::NodeImpl( ImageFileImplWeakPtr destImageFile ) : destImageFile_( destImageFile ), isAttached_( false )
|
||||
NodeImpl::NodeImpl( ImageFileImplWeakPtr destImageFile ) :
|
||||
destImageFile_( destImageFile ), isAttached_( false )
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__,
|
||||
static_cast<const char *>( __FUNCTION__ ) ); // does checking for all node type ctors
|
||||
checkImageFileOpen(
|
||||
__FILE__, __LINE__,
|
||||
static_cast<const char *>( __FUNCTION__ ) ); // does checking for all node type ctors
|
||||
}
|
||||
|
||||
void NodeImpl::checkImageFileOpen( const char *srcFileName, int srcLineNumber, const char *srcFunctionName ) const
|
||||
void NodeImpl::checkImageFileOpen( const char *srcFileName, int srcLineNumber,
|
||||
const char *srcFunctionName ) const
|
||||
{
|
||||
/// Throw an exception if destImageFile (destImageFile_) isn't open
|
||||
// Throw an exception if destImageFile (destImageFile_) isn't open
|
||||
ImageFileImplSharedPtr destImageFile( destImageFile_ );
|
||||
if ( !destImageFile->isOpen() )
|
||||
{
|
||||
throw E57Exception( E57_ERROR_IMAGEFILE_NOT_OPEN, "fileName=" + destImageFile->fileName(), srcFileName,
|
||||
srcLineNumber, srcFunctionName );
|
||||
throw E57Exception( ErrorImageFileNotOpen, "fileName=" + destImageFile->fileName(),
|
||||
srcFileName, srcLineNumber, srcFunctionName );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +58,7 @@ bool NodeImpl::isRoot() const
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
return parent_.expired();
|
||||
};
|
||||
}
|
||||
|
||||
NodeImplSharedPtr NodeImpl::parent()
|
||||
{
|
||||
@@ -62,7 +66,7 @@ NodeImplSharedPtr NodeImpl::parent()
|
||||
|
||||
if ( isRoot() )
|
||||
{
|
||||
/// If is root, then has self as parent (by convention)
|
||||
// If is root, then has self as parent (by convention)
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
@@ -100,12 +104,12 @@ ustring NodeImpl::relativePathName( const NodeImplSharedPtr &origin, ustring chi
|
||||
|
||||
if ( isRoot() )
|
||||
{
|
||||
/// Got to top and didn't find origin, must be error
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL,
|
||||
"this->elementName=" + this->elementName() + " childPathName=" + childPathName );
|
||||
// Got to top and didn't find origin, must be error
|
||||
throw E57_EXCEPTION2( ErrorInternal, "this->elementName=" + this->elementName() +
|
||||
" childPathName=" + childPathName );
|
||||
}
|
||||
|
||||
/// Assemble relativePathName from right to left, recursively
|
||||
// Assemble relativePathName from right to left, recursively
|
||||
NodeImplSharedPtr p( parent_ );
|
||||
|
||||
if ( childPathName.empty() )
|
||||
@@ -125,7 +129,7 @@ ustring NodeImpl::elementName() const
|
||||
|
||||
ImageFileImplSharedPtr NodeImpl::destImageFile()
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
return ImageFileImplSharedPtr( destImageFile_ );
|
||||
}
|
||||
|
||||
@@ -138,15 +142,14 @@ bool NodeImpl::isAttached() const
|
||||
|
||||
void NodeImpl::setAttachedRecursive()
|
||||
{
|
||||
/// Non-terminal node types (Structure, Vector, CompressedVector) will
|
||||
/// override this virtual function, to mark their children, codecs,
|
||||
/// prototypes
|
||||
// Non-terminal node types (Structure, Vector, CompressedVector) will override this virtual
|
||||
// function, to mark their children, codecs, prototypes
|
||||
isAttached_ = true;
|
||||
}
|
||||
|
||||
ustring NodeImpl::imageFileName() const
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
ImageFileImplSharedPtr imf( destImageFile_ );
|
||||
|
||||
return imf->fileName();
|
||||
@@ -154,27 +157,28 @@ ustring NodeImpl::imageFileName() const
|
||||
|
||||
void NodeImpl::setParent( NodeImplSharedPtr parent, const ustring &elementName )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// First check if our parent_ is already set, throw
|
||||
/// E57_ERROR_ALREADY_HAS_PARENT The isAttached_ condition is to catch two
|
||||
/// errors:
|
||||
/// 1) if user attempts to use the ImageFile root as a child (e.g.
|
||||
/// root.set("x", root)) 2) if user attempts to reuse codecs or prototype
|
||||
/// trees of a CompressedVectorNode
|
||||
/// ??? what if CV not attached yet?
|
||||
// First check if our parent_ is already set, throw
|
||||
// ErrorAlreadyHasParent The isAttached_ condition is to catch two
|
||||
// errors:
|
||||
// 1) if user attempts to use the ImageFile root as a child (e.g.
|
||||
// root.set("x", root)) 2) if user attempts to reuse codecs or prototype
|
||||
// trees of a CompressedVectorNode
|
||||
// ??? what if CV not attached yet?
|
||||
if ( !parent_.expired() || isAttached_ )
|
||||
{
|
||||
/// ??? does caller do setParent first, so state is not messed up when
|
||||
/// throw?
|
||||
throw E57_EXCEPTION2( E57_ERROR_ALREADY_HAS_PARENT,
|
||||
"this->pathName=" + this->pathName() + " newParent->pathName=" + parent->pathName() );
|
||||
// ??? does caller do setParent first, so state is not messed up when
|
||||
// throw?
|
||||
throw E57_EXCEPTION2( ErrorAlreadyHasParent,
|
||||
"this->pathName=" + this->pathName() +
|
||||
" newParent->pathName=" + parent->pathName() );
|
||||
}
|
||||
|
||||
parent_ = parent;
|
||||
elementName_ = elementName;
|
||||
|
||||
/// If parent is attached then we are attached (and all of our children)
|
||||
// If parent is attached then we are attached (and all of our children)
|
||||
if ( parent->isAttached() )
|
||||
{
|
||||
setAttachedRecursive();
|
||||
@@ -183,7 +187,7 @@ void NodeImpl::setParent( NodeImplSharedPtr parent, const ustring &elementName )
|
||||
|
||||
NodeImplSharedPtr NodeImpl::getRoot()
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
NodeImplSharedPtr p( shared_from_this() );
|
||||
while ( !p->isRoot() )
|
||||
{
|
||||
@@ -196,92 +200,90 @@ NodeImplSharedPtr NodeImpl::getRoot()
|
||||
//??? use visitor?
|
||||
bool NodeImpl::isTypeConstrained()
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
/// A node is type constrained if any of its parents is an homo VECTOR or
|
||||
/// COMPRESSED_VECTOR with more than one child
|
||||
// don't checkImageFileOpen
|
||||
// A node is type constrained if any of its parents is an homo VECTOR or COMPRESSED_VECTOR with
|
||||
// more than one child
|
||||
NodeImplSharedPtr p( shared_from_this() );
|
||||
|
||||
while ( !p->isRoot() )
|
||||
{
|
||||
/// We have a parent since we are not root
|
||||
// We have a parent since we are not root
|
||||
p = NodeImplSharedPtr( p->parent_ ); //??? check if bad ptr?
|
||||
|
||||
switch ( p->type() )
|
||||
{
|
||||
case E57_VECTOR:
|
||||
case TypeVector:
|
||||
{
|
||||
/// Downcast to shared_ptr<VectorNodeImpl>
|
||||
// Downcast to shared_ptr<VectorNodeImpl>
|
||||
std::shared_ptr<VectorNodeImpl> ai( std::static_pointer_cast<VectorNodeImpl>( p ) );
|
||||
|
||||
/// If homogeneous vector and have more than one child, then can't
|
||||
/// change them
|
||||
// If homogeneous vector and have more than one child, then can't change them
|
||||
if ( !ai->allowHeteroChildren() && ai->childCount() > 1 )
|
||||
{
|
||||
return ( true );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E57_COMPRESSED_VECTOR:
|
||||
/// Can't make any type changes to CompressedVector prototype. ???
|
||||
/// what if hasn't been written to yet
|
||||
case TypeCompressedVector:
|
||||
// Can't make any type changes to CompressedVector prototype. ???
|
||||
// what if hasn't been written to yet
|
||||
return ( true );
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/// Didn't find any constraining VECTORs or COMPRESSED_VECTORs in path above
|
||||
/// us, so our type is not constrained.
|
||||
// Didn't find any constraining VECTORs or COMPRESSED_VECTORs in path above us, so our type is
|
||||
// not constrained.
|
||||
return ( false );
|
||||
}
|
||||
|
||||
NodeImplSharedPtr NodeImpl::get( const ustring &pathName )
|
||||
{
|
||||
/// This is common virtual function for terminal E57 element types: Integer,
|
||||
/// ScaledInteger, Float, Blob. The non-terminal types override this virtual
|
||||
/// function. Only absolute pathNames make any sense here, because the
|
||||
/// terminal types can't have children, so relative pathNames are illegal.
|
||||
// This is common virtual function for terminal E57 element types: Integer, ScaledInteger, Float,
|
||||
// Blob. The non-terminal types override this virtual function. Only absolute pathNames make any
|
||||
// sense here, because the terminal types can't have children, so relative pathNames are illegal.
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef VALIDATE_BASIC
|
||||
_verifyPathNameAbsolute( pathName );
|
||||
#endif
|
||||
|
||||
NodeImplSharedPtr root = _verifyAndGetRoot();
|
||||
|
||||
/// Forward call to the non-terminal root node
|
||||
// Forward call to the non-terminal root node
|
||||
return root->get( pathName );
|
||||
}
|
||||
|
||||
void NodeImpl::set( const ustring &pathName, NodeImplSharedPtr ni, bool autoPathCreate )
|
||||
{
|
||||
/// This is common virtual function for terminal E57 element types: Integer,
|
||||
/// ScaledInteger, Float, Blob. The non-terminal types override this virtual
|
||||
/// function. Only absolute pathNames make any sense here, because the
|
||||
/// terminal types can't have children, so relative pathNames are illegal.
|
||||
// This is common virtual function for terminal E57 element types: Integer, ScaledInteger,
|
||||
// Float, Blob. The non-terminal types override this virtual function. Only absolute pathNames
|
||||
// make any sense here, because the terminal types can't have children, so relative pathNames are
|
||||
// illegal.
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef VALIDATE_BASIC
|
||||
_verifyPathNameAbsolute( pathName );
|
||||
#endif
|
||||
|
||||
NodeImplSharedPtr root = _verifyAndGetRoot();
|
||||
|
||||
/// Forward call to the non-terminal root node
|
||||
// Forward call to the non-terminal root node
|
||||
root->set( pathName, ni, autoPathCreate );
|
||||
}
|
||||
|
||||
void NodeImpl::set( const StringList & /*fields*/, unsigned /*level*/, NodeImplSharedPtr /*ni*/,
|
||||
bool /*autoPathCreate*/ )
|
||||
{
|
||||
/// If get here, then tried to call set(fields...) on NodeImpl that wasn't a
|
||||
/// StructureNodeImpl, so that's an error
|
||||
throw E57_EXCEPTION1( E57_ERROR_BAD_PATH_NAME ); //???
|
||||
// If get here, then tried to call set(fields...) on NodeImpl that wasn't a StructureNodeImpl,
|
||||
// so that's an error
|
||||
throw E57_EXCEPTION1( ErrorBadPathName ); //???
|
||||
}
|
||||
|
||||
void NodeImpl::checkBuffers( const std::vector<SourceDestBuffer> &sdbufs,
|
||||
bool allowMissing ) //??? convert sdbufs to vector of shared_ptr
|
||||
{
|
||||
/// this node is prototype of CompressedVector
|
||||
// this node is prototype of CompressedVector
|
||||
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
|
||||
StringSet pathNames;
|
||||
|
||||
@@ -289,42 +291,41 @@ void NodeImpl::checkBuffers( const std::vector<SourceDestBuffer> &sdbufs,
|
||||
{
|
||||
ustring pathName = sdbufs.at( i ).impl()->pathName();
|
||||
|
||||
/// Check that all buffers are same size
|
||||
// Check that all buffers are same size
|
||||
if ( sdbufs.at( i ).impl()->capacity() != sdbufs.at( 0 ).impl()->capacity() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BUFFER_SIZE_MISMATCH,
|
||||
"this->pathName=" + this->pathName() + " sdbuf.pathName=" + pathName +
|
||||
" firstCapacity=" + toString( sdbufs.at( 0 ).impl()->capacity() ) +
|
||||
" secondCapacity=" + toString( sdbufs.at( i ).impl()->capacity() ) );
|
||||
throw E57_EXCEPTION2(
|
||||
ErrorBufferSizeMismatch,
|
||||
"this->pathName=" + this->pathName() + " sdbuf.pathName=" + pathName +
|
||||
" firstCapacity=" + toString( sdbufs.at( 0 ).impl()->capacity() ) +
|
||||
" secondCapacity=" + toString( sdbufs.at( i ).impl()->capacity() ) );
|
||||
}
|
||||
|
||||
/// Add each pathName to set, error if already in set (a duplicate
|
||||
/// pathName in sdbufs)
|
||||
// Add each pathName to set, error if already in set (a duplicate pathName in sdbufs)
|
||||
if ( !pathNames.insert( pathName ).second )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BUFFER_DUPLICATE_PATHNAME,
|
||||
"this->pathName=" + this->pathName() + " sdbuf.pathName=" + pathName );
|
||||
throw E57_EXCEPTION2( ErrorBufferDuplicatePathName, "this->pathName=" + this->pathName() +
|
||||
" sdbuf.pathName=" + pathName );
|
||||
}
|
||||
|
||||
/// Check no bad fields in sdbufs
|
||||
// Check no bad fields in sdbufs
|
||||
if ( !isDefined( pathName ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_PATH_UNDEFINED,
|
||||
"this->pathName=" + this->pathName() + " sdbuf.pathName=" + pathName );
|
||||
throw E57_EXCEPTION2( ErrorPathUndefined, "this->pathName=" + this->pathName() +
|
||||
" sdbuf.pathName=" + pathName );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !allowMissing )
|
||||
{
|
||||
/// Traverse tree recursively, checking that all nodes are listed in
|
||||
/// sdbufs
|
||||
// Traverse tree recursively, checking that all nodes are listed in sdbufs
|
||||
checkLeavesInSet( pathNames, shared_from_this() );
|
||||
}
|
||||
}
|
||||
|
||||
bool NodeImpl::findTerminalPosition( const NodeImplSharedPtr &target, uint64_t &countFromLeft )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
|
||||
if ( this == &*target ) //??? ok?
|
||||
{
|
||||
@@ -333,11 +334,11 @@ bool NodeImpl::findTerminalPosition( const NodeImplSharedPtr &target, uint64_t &
|
||||
|
||||
switch ( type() )
|
||||
{
|
||||
case E57_STRUCTURE:
|
||||
case TypeStructure:
|
||||
{
|
||||
auto sni = static_cast<StructureNodeImpl *>( this );
|
||||
|
||||
/// Recursively visit child nodes
|
||||
// Recursively visit child nodes
|
||||
int64_t childCount = sni->childCount();
|
||||
for ( int64_t i = 0; i < childCount; ++i )
|
||||
{
|
||||
@@ -349,11 +350,11 @@ bool NodeImpl::findTerminalPosition( const NodeImplSharedPtr &target, uint64_t &
|
||||
}
|
||||
break;
|
||||
|
||||
case E57_VECTOR:
|
||||
case TypeVector:
|
||||
{
|
||||
auto vni = static_cast<VectorNodeImpl *>( this );
|
||||
|
||||
/// Recursively visit child nodes
|
||||
// Recursively visit child nodes
|
||||
int64_t childCount = vni->childCount();
|
||||
for ( int64_t i = 0; i < childCount; ++i )
|
||||
{
|
||||
@@ -365,14 +366,14 @@ bool NodeImpl::findTerminalPosition( const NodeImplSharedPtr &target, uint64_t &
|
||||
}
|
||||
break;
|
||||
|
||||
case E57_COMPRESSED_VECTOR:
|
||||
case TypeCompressedVector:
|
||||
break; //??? for now, don't search into contents of compressed vector
|
||||
|
||||
case E57_INTEGER:
|
||||
case E57_SCALED_INTEGER:
|
||||
case E57_FLOAT:
|
||||
case E57_STRING:
|
||||
case E57_BLOB:
|
||||
case TypeInteger:
|
||||
case TypeScaledInteger:
|
||||
case TypeFloat:
|
||||
case TypeString:
|
||||
case TypeBlob:
|
||||
countFromLeft++;
|
||||
break;
|
||||
}
|
||||
@@ -380,20 +381,22 @@ bool NodeImpl::findTerminalPosition( const NodeImplSharedPtr &target, uint64_t &
|
||||
return ( false );
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void NodeImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
os << space( indent ) << "elementName: " << elementName_ << std::endl;
|
||||
os << space( indent ) << "isAttached: " << isAttached_ << std::endl;
|
||||
os << space( indent ) << "path: " << pathName() << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VALIDATE_BASIC
|
||||
bool NodeImpl::_verifyPathNameAbsolute( const ustring &inPathName )
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
|
||||
/// Parse to determine if pathName is absolute
|
||||
// Parse to determine if pathName is absolute
|
||||
bool isRelative = false;
|
||||
std::vector<ustring> fields;
|
||||
ImageFileImplSharedPtr imf( destImageFile_ );
|
||||
@@ -401,30 +404,31 @@ bool NodeImpl::_verifyPathNameAbsolute( const ustring &inPathName )
|
||||
imf->pathNameParse( inPathName, isRelative,
|
||||
fields ); // throws if bad pathName
|
||||
|
||||
/// If not an absolute path name, have error
|
||||
// If not an absolute path name, have error
|
||||
if ( isRelative )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "this->pathName=" + this->pathName() + " pathName=" + inPathName );
|
||||
throw E57_EXCEPTION2( ErrorBadPathName,
|
||||
"this->pathName=" + this->pathName() + " pathName=" + inPathName );
|
||||
}
|
||||
|
||||
return isRelative;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
NodeImplSharedPtr NodeImpl::_verifyAndGetRoot()
|
||||
{
|
||||
/// Find root of the tree
|
||||
// Find root of the tree
|
||||
NodeImplSharedPtr root( shared_from_this()->getRoot() );
|
||||
|
||||
/// Check to make sure root node is non-terminal type (otherwise have stack
|
||||
/// overflow).
|
||||
// Check to make sure root node is non-terminal type (otherwise have stack overflow).
|
||||
switch ( root->type() )
|
||||
{
|
||||
case E57_STRUCTURE:
|
||||
case E57_VECTOR: //??? COMPRESSED_VECTOR?
|
||||
case TypeStructure:
|
||||
case TypeVector: //??? COMPRESSED_VECTOR?
|
||||
break;
|
||||
default:
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "root invalid for this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorInternal,
|
||||
"root invalid for this->pathName=" + this->pathName() );
|
||||
}
|
||||
|
||||
return root;
|
||||
|
||||
25
src/3rdParty/libE57Format/src/NodeImpl.h
vendored
25
src/3rdParty/libE57Format/src/NodeImpl.h
vendored
@@ -31,19 +31,21 @@
|
||||
|
||||
namespace e57
|
||||
{
|
||||
|
||||
class CheckedFile;
|
||||
|
||||
class NodeImpl : public std::enable_shared_from_this<NodeImpl>
|
||||
{
|
||||
public:
|
||||
virtual NodeType type() const = 0;
|
||||
void checkImageFileOpen( const char *srcFileName, int srcLineNumber, const char *srcFunctionName ) const;
|
||||
void checkImageFileOpen( const char *srcFileName, int srcLineNumber,
|
||||
const char *srcFunctionName ) const;
|
||||
virtual bool isTypeEquivalent( NodeImplSharedPtr ni ) = 0;
|
||||
|
||||
bool isRoot() const;
|
||||
NodeImplSharedPtr parent();
|
||||
ustring pathName() const;
|
||||
ustring relativePathName( const NodeImplSharedPtr &origin, ustring childPathName = ustring() ) const;
|
||||
ustring relativePathName( const NodeImplSharedPtr &origin,
|
||||
ustring childPathName = ustring() ) const;
|
||||
ustring elementName() const;
|
||||
ImageFileImplSharedPtr destImageFile();
|
||||
|
||||
@@ -56,8 +58,10 @@ namespace e57
|
||||
bool isTypeConstrained();
|
||||
|
||||
virtual NodeImplSharedPtr get( const ustring &pathName );
|
||||
virtual void set( const ustring &pathName, NodeImplSharedPtr ni, bool autoPathCreate = false );
|
||||
virtual void set( const StringList &fields, unsigned level, NodeImplSharedPtr ni, bool autoPathCreate = false );
|
||||
virtual void set( const ustring &pathName, NodeImplSharedPtr ni,
|
||||
bool autoPathCreate = false );
|
||||
virtual void set( const StringList &fields, unsigned level, NodeImplSharedPtr ni,
|
||||
bool autoPathCreate = false );
|
||||
|
||||
virtual void checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin ) = 0;
|
||||
void checkBuffers( const std::vector<SourceDestBuffer> &sdbufs, bool allowMissing );
|
||||
@@ -68,12 +72,12 @@ namespace e57
|
||||
|
||||
virtual ~NodeImpl() = default;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
virtual void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef VALIDATE_BASIC
|
||||
bool _verifyPathNameAbsolute( const ustring &inPathName );
|
||||
#endif
|
||||
|
||||
@@ -85,12 +89,13 @@ namespace e57
|
||||
friend class Decoder;
|
||||
friend class Encoder;
|
||||
|
||||
NodeImpl( ImageFileImplWeakPtr destImageFile );
|
||||
NodeImpl &operator=( NodeImpl &n );
|
||||
explicit NodeImpl( ImageFileImplWeakPtr destImageFile );
|
||||
|
||||
virtual NodeImplSharedPtr lookup( const ustring & /*pathName*/ )
|
||||
{
|
||||
return NodeImplSharedPtr();
|
||||
return {};
|
||||
}
|
||||
|
||||
NodeImplSharedPtr getRoot();
|
||||
|
||||
ImageFileImplWeakPtr destImageFile_;
|
||||
|
||||
456
src/3rdParty/libE57Format/src/Packet.cpp
vendored
456
src/3rdParty/libE57Format/src/Packet.cpp
vendored
@@ -29,34 +29,10 @@
|
||||
|
||||
#include "CheckedFile.h"
|
||||
#include "Packet.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
struct IndexPacket
|
||||
{
|
||||
static constexpr unsigned MAX_ENTRIES = 2048;
|
||||
|
||||
const uint8_t packetType = INDEX_PACKET;
|
||||
|
||||
uint8_t packetFlags = 0; // flag bitfields
|
||||
uint16_t packetLogicalLengthMinus1 = 0;
|
||||
uint16_t entryCount = 0;
|
||||
uint8_t indexLevel = 0;
|
||||
uint8_t reserved1[9] = {}; // must be zero
|
||||
|
||||
struct IndexPacketEntry
|
||||
{
|
||||
uint64_t chunkRecordNumber = 0;
|
||||
uint64_t chunkPhysicalOffset = 0;
|
||||
} entries[MAX_ENTRIES];
|
||||
|
||||
void verify( unsigned bufferLength = 0, uint64_t totalRecordCount = 0, uint64_t fileSize = 0 ) const;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct EmptyPacketHeader
|
||||
{
|
||||
const uint8_t packetType = EMPTY_PACKET;
|
||||
@@ -66,7 +42,7 @@ struct EmptyPacketHeader
|
||||
|
||||
void verify( unsigned bufferLength = 0 ) const; //???use
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
};
|
||||
@@ -74,62 +50,64 @@ struct EmptyPacketHeader
|
||||
//=============================================================================
|
||||
// PacketReadCache
|
||||
|
||||
PacketReadCache::PacketReadCache( CheckedFile *cFile, unsigned packetCount ) : cFile_( cFile ), entries_( packetCount )
|
||||
PacketReadCache::PacketReadCache( CheckedFile *cFile, unsigned packetCount ) :
|
||||
cFile_( cFile ), entries_( packetCount )
|
||||
{
|
||||
if ( packetCount == 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetCount=" + toString( packetCount ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "packetCount=" + toString( packetCount ) );
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<PacketLock> PacketReadCache::lock( uint64_t packetLogicalOffset, char *&pkt )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << "PacketReadCache::lock() called, packetLogicalOffset=" << packetLogicalOffset << std::endl;
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "PacketReadCache::lock() called, packetLogicalOffset=" << packetLogicalOffset
|
||||
<< std::endl;
|
||||
#endif
|
||||
|
||||
/// Only allow one locked packet at a time.
|
||||
// Only allow one locked packet at a time.
|
||||
if ( lockCount_ > 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "lockCount=" + toString( lockCount_ ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "lockCount=" + toString( lockCount_ ) );
|
||||
}
|
||||
|
||||
/// Offset can't be 0
|
||||
// Offset can't be 0
|
||||
if ( packetLogicalOffset == 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetLogicalOffset=" + toString( packetLogicalOffset ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal,
|
||||
"packetLogicalOffset=" + toString( packetLogicalOffset ) );
|
||||
}
|
||||
|
||||
/// Linear scan for matching packet offset in cache
|
||||
// Linear scan for matching packet offset in cache
|
||||
for ( unsigned i = 0; i < entries_.size(); ++i )
|
||||
{
|
||||
auto &entry = entries_[i];
|
||||
|
||||
if ( packetLogicalOffset == entry.logicalOffset_ )
|
||||
{
|
||||
/// Found a match, so don't have to read anything
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
// Found a match, so don't have to read anything
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " Found matching cache entry, index=" << i << std::endl;
|
||||
#endif
|
||||
/// Mark entry with current useCount (keeps track of age of entry).
|
||||
// Mark entry with current useCount (keeps track of age of entry).
|
||||
entry.lastUsed_ = ++useCount_;
|
||||
|
||||
/// Publish buffer address to caller
|
||||
// Publish buffer address to caller
|
||||
pkt = entry.buffer_;
|
||||
|
||||
/// Create lock so we are sure that we will be unlocked when use is
|
||||
/// finished.
|
||||
// Create lock so we are sure that we will be unlocked when use is finished.
|
||||
std::unique_ptr<PacketLock> plock( new PacketLock( this, i ) );
|
||||
|
||||
/// Increment cache lock just before return
|
||||
// Increment cache lock just before return
|
||||
++lockCount_;
|
||||
|
||||
return plock;
|
||||
}
|
||||
}
|
||||
/// Get here if didn't find a match already in cache.
|
||||
// Get here if didn't find a match already in cache.
|
||||
|
||||
/// Find least recently used (LRU) packet buffer
|
||||
// Find least recently used (LRU) packet buffer
|
||||
unsigned oldestEntry = 0;
|
||||
unsigned oldestUsed = entries_.at( 0 ).lastUsed_;
|
||||
|
||||
@@ -143,19 +121,19 @@ std::unique_ptr<PacketLock> PacketReadCache::lock( uint64_t packetLogicalOffset,
|
||||
oldestUsed = entry.lastUsed_;
|
||||
}
|
||||
}
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " Oldest entry=" << oldestEntry << " lastUsed=" << oldestUsed << std::endl;
|
||||
#endif
|
||||
|
||||
readPacket( oldestEntry, packetLogicalOffset );
|
||||
|
||||
/// Publish buffer address to caller
|
||||
// Publish buffer address to caller
|
||||
pkt = entries_[oldestEntry].buffer_;
|
||||
|
||||
/// Create lock so we are sure we will be unlocked when use is finished.
|
||||
// Create lock so we are sure we will be unlocked when use is finished.
|
||||
std::unique_ptr<PacketLock> plock( new PacketLock( this, oldestEntry ) );
|
||||
|
||||
/// Increment cache lock just before return
|
||||
// Increment cache lock just before return
|
||||
++lockCount_;
|
||||
|
||||
return plock;
|
||||
@@ -163,15 +141,16 @@ std::unique_ptr<PacketLock> PacketReadCache::lock( uint64_t packetLogicalOffset,
|
||||
|
||||
void PacketReadCache::unlock( unsigned cacheIndex )
|
||||
{
|
||||
(void)cacheIndex;
|
||||
//??? why lockedEntry not used?
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "PacketReadCache::unlock() called, cacheIndex=" << cacheIndex << std::endl;
|
||||
#else
|
||||
E57_UNUSED( cacheIndex );
|
||||
#endif
|
||||
|
||||
if ( lockCount_ != 1 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "lockCount=" + toString( lockCount_ ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "lockCount=" + toString( lockCount_ ) );
|
||||
}
|
||||
|
||||
--lockCount_;
|
||||
@@ -179,35 +158,34 @@ void PacketReadCache::unlock( unsigned cacheIndex )
|
||||
|
||||
void PacketReadCache::readPacket( unsigned oldestEntry, uint64_t packetLogicalOffset )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "PacketReadCache::readPacket() called, oldestEntry=" << oldestEntry
|
||||
<< " packetLogicalOffset=" << packetLogicalOffset << std::endl;
|
||||
#endif
|
||||
|
||||
/// Read header of packet first to get length. Use EmptyPacketHeader since
|
||||
/// it has the fields common to all packets.
|
||||
// Read header of packet first to get length. Use EmptyPacketHeader since it has the fields
|
||||
// common to all packets.
|
||||
EmptyPacketHeader header;
|
||||
|
||||
cFile_->seek( packetLogicalOffset, CheckedFile::Logical );
|
||||
cFile_->read( reinterpret_cast<char *>( &header ), sizeof( header ) );
|
||||
|
||||
/// Can't verify packet header here, because it is not really an
|
||||
/// EmptyPacketHeader.
|
||||
// Can't verify packet header here, because it is not really an EmptyPacketHeader.
|
||||
unsigned packetLength = header.packetLogicalLengthMinus1 + 1;
|
||||
|
||||
/// Be paranoid about packetLength before read
|
||||
// Be paranoid about packetLength before read
|
||||
if ( packetLength > DATA_PACKET_MAX )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "packetLength=" + toString( packetLength ) );
|
||||
}
|
||||
|
||||
auto &entry = entries_.at( oldestEntry );
|
||||
|
||||
/// Now read in whole packet into preallocated buffer_. Note buffer is
|
||||
// Now read in whole packet into preallocated buffer_. Note buffer is
|
||||
cFile_->seek( packetLogicalOffset, CheckedFile::Logical );
|
||||
cFile_->read( entry.buffer_, packetLength );
|
||||
|
||||
/// Verify that packet is good.
|
||||
// Verify that packet is good.
|
||||
switch ( header.packetType )
|
||||
{
|
||||
case DATA_PACKET:
|
||||
@@ -215,7 +193,7 @@ void PacketReadCache::readPacket( unsigned oldestEntry, uint64_t packetLogicalOf
|
||||
auto dpkt = reinterpret_cast<DataPacket *>( entry.buffer_ );
|
||||
|
||||
dpkt->verify( packetLength );
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " data packet:" << std::endl;
|
||||
dpkt->dump( 4 ); //???
|
||||
#endif
|
||||
@@ -226,7 +204,7 @@ void PacketReadCache::readPacket( unsigned oldestEntry, uint64_t packetLogicalOf
|
||||
auto ipkt = reinterpret_cast<IndexPacket *>( entry.buffer_ );
|
||||
|
||||
ipkt->verify( packetLength );
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " index packet:" << std::endl;
|
||||
ipkt->dump( 4 ); //???
|
||||
#endif
|
||||
@@ -237,24 +215,24 @@ void PacketReadCache::readPacket( unsigned oldestEntry, uint64_t packetLogicalOf
|
||||
auto hp = reinterpret_cast<EmptyPacketHeader *>( entry.buffer_ );
|
||||
|
||||
hp->verify( packetLength );
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << " empty packet:" << std::endl;
|
||||
hp->dump( 4 ); //???
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetType=" + toString( header.packetType ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "packetType=" + toString( header.packetType ) );
|
||||
}
|
||||
|
||||
entry.logicalOffset_ = packetLogicalOffset;
|
||||
|
||||
/// Mark entry with current useCount (keeps track of age of entry).
|
||||
/// This is a cache, so a small hiccup when useCount_ overflows won't hurt.
|
||||
// Mark entry with current useCount (keeps track of age of entry).
|
||||
// This is a cache, so a small hiccup when useCount_ overflows won't hurt.
|
||||
entry.lastUsed_ = ++useCount_;
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void PacketReadCache::dump( int indent, std::ostream &os )
|
||||
{
|
||||
os << space( indent ) << "lockCount: " << lockCount_ << std::endl;
|
||||
@@ -290,9 +268,9 @@ void PacketReadCache::dump( int indent, std::ostream &os )
|
||||
break;
|
||||
default:
|
||||
throw E57_EXCEPTION2(
|
||||
E57_ERROR_INTERNAL,
|
||||
"packetType=" +
|
||||
toString( reinterpret_cast<EmptyPacketHeader *>( entries_.at( i ).buffer_ )->packetType ) );
|
||||
ErrorInternal, "packetType=" + toString( reinterpret_cast<EmptyPacketHeader *>(
|
||||
entries_.at( i ).buffer_ )
|
||||
->packetType ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,21 +280,22 @@ void PacketReadCache::dump( int indent, std::ostream &os )
|
||||
//=============================================================================
|
||||
// PacketLock
|
||||
|
||||
PacketLock::PacketLock( PacketReadCache *cache, unsigned cacheIndex ) : cache_( cache ), cacheIndex_( cacheIndex )
|
||||
PacketLock::PacketLock( PacketReadCache *cache, unsigned cacheIndex ) :
|
||||
cache_( cache ), cacheIndex_( cacheIndex )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "PacketLock() called" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
PacketLock::~PacketLock()
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "~PacketLock() called" << std::endl;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
/// Note cache must live longer than lock, this is reasonable assumption.
|
||||
// Note cache must live longer than lock, this is reasonable assumption.
|
||||
cache_->unlock( cacheIndex_ );
|
||||
}
|
||||
catch ( ... )
|
||||
@@ -330,8 +309,7 @@ PacketLock::~PacketLock()
|
||||
|
||||
DataPacketHeader::DataPacketHeader()
|
||||
{
|
||||
/// Double check that packet struct is correct length. Watch out for RTTI
|
||||
/// increasing the size.
|
||||
// Double check that packet struct is correct length. Watch out for RTTI increasing the size.
|
||||
static_assert( sizeof( DataPacketHeader ) == 6, "Unexpected size of DataPacketHeader" );
|
||||
}
|
||||
|
||||
@@ -344,54 +322,60 @@ void DataPacketHeader::reset()
|
||||
|
||||
void DataPacketHeader::verify( unsigned bufferLength ) const
|
||||
{
|
||||
/// Verify that packet is correct type
|
||||
// Verify that packet is correct type
|
||||
// cppcheck-suppress knownConditionTrueFalse; (data is read as a blob, so the const might not
|
||||
// be valid)
|
||||
if ( packetType != DATA_PACKET )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( packetType ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket,
|
||||
"expected Data; packetType=" + toString( packetType ) );
|
||||
}
|
||||
|
||||
/// ??? check reserved flags zero?
|
||||
// ??? check reserved flags zero?
|
||||
|
||||
/// Check packetLength is at least large enough to hold header
|
||||
// Check packetLength is at least large enough to hold header
|
||||
unsigned packetLength = packetLogicalLengthMinus1 + 1;
|
||||
if ( packetLength < sizeof( *this ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "DATA; packetLength=" + toString( packetLength ) );
|
||||
}
|
||||
|
||||
/// Check packet length is multiple of 4
|
||||
// Check packet length is multiple of 4
|
||||
if ( packetLength % 4 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "DATA; packetLength=" + toString( packetLength ) );
|
||||
}
|
||||
|
||||
/// Check actual packet length is large enough.
|
||||
// Check actual packet length is large enough.
|
||||
if ( bufferLength > 0 && packetLength > bufferLength )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
|
||||
"packetLength=" + toString( packetLength ) + " bufferLength=" + toString( bufferLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "DATA; packetLength=" + toString( packetLength ) +
|
||||
" bufferLength=" + toString( bufferLength ) );
|
||||
}
|
||||
|
||||
/// Make sure there is at least one entry in packet ??? 0 record cvect
|
||||
/// allowed?
|
||||
if ( bytestreamCount == 0 )
|
||||
// Make sure there is at least one entry in packet
|
||||
if ( hasRecords() && ( bytestreamCount == 0 ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "bytestreamCount=" + toString( bytestreamCount ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket,
|
||||
"DATA; bytestreamCount=" + toString( bytestreamCount ) );
|
||||
}
|
||||
|
||||
/// Check packet is at least long enough to hold bytestreamBufferLength array
|
||||
if ( sizeof( DataPacketHeader ) + 2 * bytestreamCount > packetLength )
|
||||
// Check packet is at least long enough to hold bytestreamBufferLength array
|
||||
if ( ( sizeof( DataPacketHeader ) + 2 * bytestreamCount ) > packetLength )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) +
|
||||
" bytestreamCount=" + toString( bytestreamCount ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket,
|
||||
"DATA; packetLength=" + toString( packetLength ) +
|
||||
" bytestreamCount=" + toString( bytestreamCount ) );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void DataPacketHeader::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
os << space( indent ) << "packetType: " << static_cast<unsigned>( packetType ) << std::endl;
|
||||
os << space( indent ) << "packetFlags: " << static_cast<unsigned>( packetFlags ) << std::endl;
|
||||
os << space( indent ) << "packetType: " << static_cast<unsigned>( packetType )
|
||||
<< std::endl;
|
||||
os << space( indent ) << "packetFlags: " << static_cast<unsigned>( packetFlags )
|
||||
<< std::endl;
|
||||
os << space( indent ) << "packetLogicalLengthMinus1: " << packetLogicalLengthMinus1 << std::endl;
|
||||
os << space( indent ) << "bytestreamCount: " << bytestreamCount << std::endl;
|
||||
}
|
||||
@@ -402,9 +386,8 @@ void DataPacketHeader::dump( int indent, std::ostream &os ) const
|
||||
|
||||
DataPacket::DataPacket()
|
||||
{
|
||||
/// Double check that packet struct is correct length. Watch out for RTTI
|
||||
/// increasing the size.
|
||||
static_assert( sizeof( DataPacket ) == 64 * 1024, "Unexpected size of DataPacket" );
|
||||
// Double check that packet struct is correct length. Watch out for RTTI increasing the size.
|
||||
static_assert( sizeof( DataPacket ) == ( 64 * 1024 ), "Unexpected size of DataPacket" );
|
||||
}
|
||||
|
||||
void DataPacket::verify( unsigned bufferLength ) const
|
||||
@@ -413,12 +396,12 @@ void DataPacket::verify( unsigned bufferLength ) const
|
||||
// checking? need to check
|
||||
// file version#?
|
||||
|
||||
/// Verify header is good
|
||||
// Verify header is good
|
||||
auto hp = reinterpret_cast<const DataPacketHeader *>( this );
|
||||
|
||||
hp->verify( bufferLength );
|
||||
|
||||
/// Calc sum of lengths of each bytestream buffer in this packet
|
||||
// Calc sum of lengths of each bytestream buffer in this packet
|
||||
auto bsbLength = reinterpret_cast<const uint16_t *>( &payload[0] );
|
||||
unsigned totalStreamByteCount = 0;
|
||||
|
||||
@@ -427,90 +410,93 @@ void DataPacket::verify( unsigned bufferLength ) const
|
||||
totalStreamByteCount += bsbLength[i];
|
||||
}
|
||||
|
||||
/// Calc size of packet needed
|
||||
// Calc size of packet needed
|
||||
const unsigned packetLength = header.packetLogicalLengthMinus1 + 1;
|
||||
const unsigned needed = sizeof( DataPacketHeader ) + 2 * header.bytestreamCount + totalStreamByteCount;
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
const unsigned needed =
|
||||
sizeof( DataPacketHeader ) + 2 * header.bytestreamCount + totalStreamByteCount;
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "needed=" << needed << " actual=" << packetLength << std::endl; //???
|
||||
#endif
|
||||
|
||||
/// If needed is not with 3 bytes of actual packet size, have an error
|
||||
// If needed is not with 3 bytes of actual packet size, have an error
|
||||
if ( needed > packetLength || needed + 3 < packetLength )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
|
||||
"needed=" + toString( needed ) + "packetLength=" + toString( packetLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "DATA; needed=" + toString( needed ) +
|
||||
" packetLength=" + toString( packetLength ) );
|
||||
}
|
||||
|
||||
/// Verify that padding at end of packet is zero
|
||||
// Verify that padding at end of packet is zero
|
||||
for ( unsigned i = needed; i < packetLength; i++ )
|
||||
{
|
||||
if ( reinterpret_cast<const char *>( this )[i] != 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "i=" + toString( i ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "DATA; i=" + toString( i ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *DataPacket::getBytestream( unsigned bytestreamNumber, unsigned &byteCount )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "getBytestream called, bytestreamNumber=" << bytestreamNumber << std::endl;
|
||||
#endif
|
||||
|
||||
/// Verify that packet is correct type
|
||||
// Verify that packet is correct type
|
||||
if ( header.packetType != DATA_PACKET )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( header.packetType ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "packetType=" + toString( header.packetType ) );
|
||||
}
|
||||
|
||||
/// Check bytestreamNumber in bounds
|
||||
// Check bytestreamNumber in bounds
|
||||
if ( bytestreamNumber >= header.bytestreamCount )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "bytestreamNumber=" + toString( bytestreamNumber ) +
|
||||
"bytestreamCount=" + toString( header.bytestreamCount ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal,
|
||||
"bytestreamNumber=" + toString( bytestreamNumber ) +
|
||||
" bytestreamCount=" + toString( header.bytestreamCount ) );
|
||||
}
|
||||
|
||||
/// Calc positions in packet
|
||||
// Calc positions in packet
|
||||
auto bsbLength = reinterpret_cast<uint16_t *>( &payload[0] );
|
||||
auto streamBase = reinterpret_cast<char *>( &bsbLength[header.bytestreamCount] );
|
||||
|
||||
/// Sum size of preceding stream buffers to get position
|
||||
unsigned totalPreceeding = 0;
|
||||
// Sum size of preceding stream buffers to get position
|
||||
unsigned totalPreceding = 0;
|
||||
for ( unsigned i = 0; i < bytestreamNumber; i++ )
|
||||
{
|
||||
totalPreceeding += bsbLength[i];
|
||||
totalPreceding += bsbLength[i];
|
||||
}
|
||||
|
||||
byteCount = bsbLength[bytestreamNumber];
|
||||
|
||||
/// Double check buffer is completely within packet
|
||||
if ( sizeof( DataPacketHeader ) + 2 * header.bytestreamCount + totalPreceeding + byteCount >
|
||||
// Double check buffer is completely within packet
|
||||
if ( ( sizeof( DataPacketHeader ) + 2 * header.bytestreamCount + totalPreceding + byteCount ) >
|
||||
header.packetLogicalLengthMinus1 + 1U )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL,
|
||||
"bytestreamCount=" + toString( header.bytestreamCount ) + " totalPreceeding=" +
|
||||
toString( totalPreceeding ) + " byteCount=" + toString( byteCount ) +
|
||||
" packetLogicalLengthMinus1=" + toString( header.packetLogicalLengthMinus1 ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "bytestreamCount=" + toString( header.bytestreamCount ) +
|
||||
" totalPreceding=" + toString( totalPreceding ) +
|
||||
" byteCount=" + toString( byteCount ) +
|
||||
" packetLogicalLengthMinus1=" +
|
||||
toString( header.packetLogicalLengthMinus1 ) );
|
||||
}
|
||||
|
||||
/// Return start of buffer
|
||||
return ( &streamBase[totalPreceeding] );
|
||||
// Return start of buffer
|
||||
return ( &streamBase[totalPreceding] );
|
||||
}
|
||||
|
||||
unsigned DataPacket::getBytestreamBufferLength( unsigned bytestreamNumber )
|
||||
{
|
||||
//??? for now:
|
||||
unsigned byteCount;
|
||||
(void)getBytestream( bytestreamNumber, byteCount );
|
||||
getBytestream( bytestreamNumber, byteCount );
|
||||
return ( byteCount );
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void DataPacket::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
if ( header.packetType != DATA_PACKET )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetType=" + toString( header.packetType ) );
|
||||
throw E57_EXCEPTION2( ErrorInternal, "packetType=" + toString( header.packetType ) );
|
||||
}
|
||||
|
||||
reinterpret_cast<const DataPacketHeader *>( this )->dump( indent, os );
|
||||
@@ -532,8 +518,8 @@ void DataPacket::dump( int indent, std::ostream &os ) const
|
||||
p += bsbLength[i];
|
||||
if ( p - reinterpret_cast<const uint8_t *>( this ) > DATA_PACKET_MAX )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_INTERNAL,
|
||||
"size=" + toString( p - reinterpret_cast<const uint8_t *>( this ) ) );
|
||||
throw E57_EXCEPTION2(
|
||||
ErrorInternal, "size=" + toString( p - reinterpret_cast<const uint8_t *>( this ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -541,154 +527,183 @@ void DataPacket::dump( int indent, std::ostream &os ) const
|
||||
|
||||
//=============================================================================
|
||||
// IndexPacket
|
||||
|
||||
void IndexPacket::verify( unsigned bufferLength, uint64_t totalRecordCount, uint64_t fileSize ) const
|
||||
IndexPacket::IndexPacket()
|
||||
{
|
||||
(void)totalRecordCount; (void)fileSize;
|
||||
// Double check that packet struct is correct length. Watch out for RTTI increasing the size.
|
||||
// sizeof( IndexPacketHeader ) + ( MAX_ENTRIES * sizeof( IndexPacket::Entry ) )
|
||||
static_assert( sizeof( IndexPacket ) == ( 16 + ( 2048 * 16 ) ),
|
||||
"Unexpected size of IndexPacket" );
|
||||
}
|
||||
|
||||
void IndexPacket::verify( unsigned bufferLength, uint64_t totalRecordCount,
|
||||
uint64_t fileSize ) const
|
||||
{
|
||||
#if ( E57_VALIDATION_LEVEL < VALIDATION_DEEP )
|
||||
E57_UNUSED( totalRecordCount );
|
||||
E57_UNUSED( fileSize );
|
||||
#endif
|
||||
|
||||
//??? do all packets need versions? how extend without breaking older
|
||||
// checking? need to check
|
||||
// file version#?
|
||||
|
||||
/// Verify that packet is correct type
|
||||
if ( packetType != INDEX_PACKET )
|
||||
// Verify that packet is correct type
|
||||
if ( header.packetType != INDEX_PACKET )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( packetType ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket,
|
||||
"expected Index; packetType=" + toString( header.packetType ) );
|
||||
}
|
||||
|
||||
/// Check packetLength is at least large enough to hold header
|
||||
unsigned packetLength = packetLogicalLengthMinus1 + 1;
|
||||
if ( packetLength < sizeof( *this ) )
|
||||
// Check packetLength is at least large enough to hold header
|
||||
unsigned packetLength = header.packetLogicalLengthMinus1 + 1;
|
||||
if ( packetLength < sizeof( IndexPacketHeader ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket,
|
||||
"INDEX; less than size of IndexPacketHeader; packetLength=" +
|
||||
toString( packetLength ) );
|
||||
}
|
||||
|
||||
/// Check packet length is multiple of 4
|
||||
// Check packet length is multiple of 4
|
||||
if ( packetLength % 4 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "INDEX; length not multiple of 4; packetLength=" +
|
||||
toString( packetLength ) );
|
||||
}
|
||||
|
||||
/// Make sure there is at least one entry in packet ??? 0 record cvect
|
||||
/// allowed?
|
||||
if ( entryCount == 0 )
|
||||
// Make sure there is at least one entry in packet ??? 0 record cvect
|
||||
// allowed?
|
||||
if ( header.entryCount == 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "entryCount=" + toString( entryCount ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket,
|
||||
"INDEX; entryCount=" + toString( header.entryCount ) );
|
||||
}
|
||||
|
||||
/// Have to have <= 2048 entries
|
||||
if ( entryCount > MAX_ENTRIES )
|
||||
// Have to have <= 2048 entries
|
||||
if ( header.entryCount > MAX_ENTRIES )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "entryCount=" + toString( entryCount ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket,
|
||||
"INDEX; entryCount=" + toString( header.entryCount ) );
|
||||
}
|
||||
|
||||
/// Index level should be <= 5. Because (5+1)* 11 bits = 66 bits, which will
|
||||
/// cover largest number of chunks possible.
|
||||
if ( indexLevel > 5 )
|
||||
// Index level should be <= 5. Because (5+1)* 11 bits = 66 bits, which will cover largest number
|
||||
// of chunks possible.
|
||||
if ( header.indexLevel > 5 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "indexLevel=" + toString( indexLevel ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket,
|
||||
"INDEX; indexLevel=" + toString( header.indexLevel ) );
|
||||
}
|
||||
|
||||
/// Index packets above level 0 must have at least two entries (otherwise no
|
||||
/// point to existing).
|
||||
///??? check that this is in spec
|
||||
if ( indexLevel > 0 && entryCount < 2 )
|
||||
// Index packets above level 0 must have at least two entries (otherwise no point to existing).
|
||||
//??? check that this is in spec
|
||||
if ( header.indexLevel > 0 && header.entryCount < 2 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
|
||||
"indexLevel=" + toString( indexLevel ) + " entryCount=" + toString( entryCount ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "INDEX; indexLevel=" + toString( header.indexLevel ) +
|
||||
" entryCount=" + toString( header.entryCount ) );
|
||||
}
|
||||
|
||||
/// If not later version, verify reserved fields are zero. ??? test file
|
||||
/// version if (version <= E57_FORMAT_MAJOR) { //???
|
||||
for ( unsigned i = 0; i < sizeof( reserved1 ); i++ )
|
||||
// If not later version, verify reserved fields are zero. ??? test file
|
||||
// version if (version <= E57_FORMAT_MAJOR) { //???
|
||||
for ( unsigned i = 0; i < sizeof( header.reserved1 ); i++ )
|
||||
{
|
||||
if ( reserved1[i] != 0 )
|
||||
if ( header.reserved1[i] != 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "i=" + toString( i ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "i=" + toString( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
/// Check actual packet length is large enough.
|
||||
// Check actual packet length is large enough.
|
||||
if ( bufferLength > 0 && packetLength > bufferLength )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
|
||||
"packetLength=" + toString( packetLength ) + " bufferLength=" + toString( bufferLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "INDEX; packetLength=" + toString( packetLength ) +
|
||||
" bufferLength=" + toString( bufferLength ) );
|
||||
}
|
||||
|
||||
/// Check if entries will fit in space provided
|
||||
unsigned neededLength = 16 + 8 * entryCount;
|
||||
if ( packetLength < neededLength )
|
||||
// Check if entries will fit in space provided
|
||||
const unsigned cNeededLength = sizeof( IndexPacketHeader ) + sizeof( Entry ) * header.entryCount;
|
||||
if ( packetLength < cNeededLength )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
|
||||
"packetLength=" + toString( packetLength ) + " neededLength=" + toString( neededLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "INDEX; packetLength=" + toString( packetLength ) +
|
||||
" neededLength=" + toString( cNeededLength ) );
|
||||
}
|
||||
|
||||
#ifdef E57_MAX_DEBUG
|
||||
/// Verify padding at end is zero.
|
||||
#if VALIDATE_DEEP
|
||||
// Verify padding at end is zero.
|
||||
const char *p = reinterpret_cast<const char *>( this );
|
||||
for ( unsigned i = neededLength; i < packetLength; i++ )
|
||||
for ( unsigned i = cNeededLength; i < packetLength; i++ )
|
||||
{
|
||||
if ( p[i] != 0 )
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "i=" + toString( i ) );
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "INDEX; padding; i=" + toString( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify records and offsets are in sorted order
|
||||
for ( unsigned i = 0; i < entryCount; i++ )
|
||||
// Verify records and offsets are in sorted order
|
||||
for ( unsigned i = 0; i < header.entryCount; i++ )
|
||||
{
|
||||
/// Check chunkRecordNumber is in bounds
|
||||
// Check chunkRecordNumber is in bounds
|
||||
if ( totalRecordCount > 0 && entries[i].chunkRecordNumber >= totalRecordCount )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
|
||||
"i=" + toString( i ) + " chunkRecordNumber=" + toString( entries[i].chunkRecordNumber ) +
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket,
|
||||
"INDEX; record# in bounds; i=" + toString( i ) +
|
||||
" chunkRecordNumber=" + toString( entries[i].chunkRecordNumber ) +
|
||||
" totalRecordCount=" + toString( totalRecordCount ) );
|
||||
}
|
||||
|
||||
/// Check record numbers are strictly increasing
|
||||
// Check record numbers are strictly increasing
|
||||
if ( i > 0 && entries[i - 1].chunkRecordNumber >= entries[i].chunkRecordNumber )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
|
||||
"i=" + toString( i ) +
|
||||
" prevChunkRecordNumber=" + toString( entries[i - 1].chunkRecordNumber ) +
|
||||
" currentChunkRecordNumber=" + toString( entries[i].chunkRecordNumber ) );
|
||||
throw E57_EXCEPTION2(
|
||||
ErrorBadCVPacket,
|
||||
"INDEX; record numbers increasing; i=" + toString( i ) +
|
||||
" prevChunkRecordNumber=" + toString( entries[i - 1].chunkRecordNumber ) +
|
||||
" currentChunkRecordNumber=" + toString( entries[i].chunkRecordNumber ) );
|
||||
}
|
||||
|
||||
/// Check chunkPhysicalOffset is in bounds
|
||||
// Check chunkPhysicalOffset is in bounds
|
||||
if ( fileSize > 0 && entries[i].chunkPhysicalOffset >= fileSize )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "i=" + toString( i ) + " chunkPhysicalOffset=" +
|
||||
toString( entries[i].chunkPhysicalOffset ) +
|
||||
" fileSize=" + toString( fileSize ) );
|
||||
throw E57_EXCEPTION2(
|
||||
ErrorBadCVPacket,
|
||||
"INDEX; physical offset in bounds; i=" + toString( i ) + " chunkPhysicalOffset=" +
|
||||
toString( entries[i].chunkPhysicalOffset ) + " fileSize=" + toString( fileSize ) );
|
||||
}
|
||||
|
||||
/// Check chunk offsets are strictly increasing
|
||||
// Check chunk offsets are strictly increasing
|
||||
if ( i > 0 && entries[i - 1].chunkPhysicalOffset >= entries[i].chunkPhysicalOffset )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
|
||||
"i=" + toString( i ) +
|
||||
" prevChunkPhysicalOffset=" + toString( entries[i - 1].chunkPhysicalOffset ) +
|
||||
" currentChunkPhysicalOffset=" + toString( entries[i].chunkPhysicalOffset ) );
|
||||
throw E57_EXCEPTION2(
|
||||
ErrorBadCVPacket,
|
||||
"INDEX; chunk offsets increasing; i=" + toString( i ) +
|
||||
" prevChunkPhysicalOffset=" + toString( entries[i - 1].chunkPhysicalOffset ) +
|
||||
" currentChunkPhysicalOffset=" + toString( entries[i].chunkPhysicalOffset ) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void IndexPacket::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
os << space( indent ) << "packetType: " << static_cast<unsigned>( packetType ) << std::endl;
|
||||
os << space( indent ) << "packetFlags: " << static_cast<unsigned>( packetFlags ) << std::endl;
|
||||
os << space( indent ) << "packetLogicalLengthMinus1: " << packetLogicalLengthMinus1 << std::endl;
|
||||
os << space( indent ) << "entryCount: " << entryCount << std::endl;
|
||||
os << space( indent ) << "indexLevel: " << indexLevel << std::endl;
|
||||
os << space( indent )
|
||||
<< "packetType: " << static_cast<unsigned>( header.packetType ) << std::endl;
|
||||
os << space( indent )
|
||||
<< "packetFlags: " << static_cast<unsigned>( header.packetFlags ) << std::endl;
|
||||
os << space( indent ) << "packetLogicalLengthMinus1: " << header.packetLogicalLengthMinus1
|
||||
<< std::endl;
|
||||
os << space( indent ) << "entryCount: " << header.entryCount << std::endl;
|
||||
os << space( indent ) << "indexLevel: " << header.indexLevel << std::endl;
|
||||
unsigned i;
|
||||
for ( i = 0; i < entryCount && i < 10; i++ )
|
||||
for ( i = 0; i < header.entryCount && i < 10; i++ )
|
||||
{
|
||||
os << space( indent ) << "entry[" << i << "]:" << std::endl;
|
||||
os << space( indent + 4 ) << "chunkRecordNumber: " << entries[i].chunkRecordNumber << std::endl;
|
||||
os << space( indent + 4 ) << "chunkPhysicalOffset: " << entries[i].chunkPhysicalOffset << std::endl;
|
||||
os << space( indent + 4 ) << "chunkRecordNumber: " << entries[i].chunkRecordNumber
|
||||
<< std::endl;
|
||||
os << space( indent + 4 ) << "chunkPhysicalOffset: " << entries[i].chunkPhysicalOffset
|
||||
<< std::endl;
|
||||
}
|
||||
if ( i < entryCount )
|
||||
if ( i < header.entryCount )
|
||||
{
|
||||
os << space( indent ) << entryCount - i << "more entries unprinted..." << std::endl;
|
||||
os << space( indent ) << header.entryCount - i << "more entries unprinted..." << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -698,37 +713,38 @@ void IndexPacket::dump( int indent, std::ostream &os ) const
|
||||
|
||||
void EmptyPacketHeader::verify( unsigned bufferLength ) const
|
||||
{
|
||||
/// Verify that packet is correct type
|
||||
// Verify that packet is correct type
|
||||
if ( packetType != EMPTY_PACKET )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( packetType ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "packetType=" + toString( packetType ) );
|
||||
}
|
||||
|
||||
/// Check packetLength is at least large enough to hold header
|
||||
// Check packetLength is at least large enough to hold header
|
||||
unsigned packetLength = packetLogicalLengthMinus1 + 1;
|
||||
if ( packetLength < sizeof( *this ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "packetLength=" + toString( packetLength ) );
|
||||
}
|
||||
|
||||
/// Check packet length is multiple of 4
|
||||
// Check packet length is multiple of 4
|
||||
if ( packetLength % 4 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "packetLength=" + toString( packetLength ) );
|
||||
}
|
||||
|
||||
/// Check actual packet length is large enough.
|
||||
// Check actual packet length is large enough.
|
||||
if ( bufferLength > 0 && packetLength > bufferLength )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
|
||||
"packetLength=" + toString( packetLength ) + " bufferLength=" + toString( bufferLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVPacket, "packetLength=" + toString( packetLength ) +
|
||||
" bufferLength=" + toString( bufferLength ) );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void EmptyPacketHeader::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
os << space( indent ) << "packetType: " << static_cast<unsigned>( packetType ) << std::endl;
|
||||
os << space( indent ) << "packetType: " << static_cast<unsigned>( packetType )
|
||||
<< std::endl;
|
||||
os << space( indent ) << "packetLogicalLengthMinus1: " << packetLogicalLengthMinus1 << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
70
src/3rdParty/libE57Format/src/Packet.h
vendored
70
src/3rdParty/libE57Format/src/Packet.h
vendored
@@ -37,7 +37,7 @@ namespace e57
|
||||
class CheckedFile;
|
||||
class PacketLock;
|
||||
|
||||
/// Packet types (in a compressed vector section)
|
||||
// Packet types (in a compressed vector section)
|
||||
enum
|
||||
{
|
||||
INDEX_PACKET = 0,
|
||||
@@ -45,7 +45,7 @@ namespace e57
|
||||
EMPTY_PACKET,
|
||||
};
|
||||
|
||||
/// maximum size of CompressedVector binary data packet
|
||||
// Maximum size of CompressedVector binary data packet
|
||||
constexpr int DATA_PACKET_MAX = ( 64 * 1024 );
|
||||
|
||||
class PacketReadCache
|
||||
@@ -56,13 +56,14 @@ namespace e57
|
||||
std::unique_ptr<PacketLock> lock( uint64_t packetLogicalOffset,
|
||||
char *&pkt ); //??? pkt could be const
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout );
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/// Only PacketLock can unlock the cache
|
||||
friend class PacketLock;
|
||||
|
||||
// Only PacketLock can unlock the cache
|
||||
void unlock( unsigned cacheIndex );
|
||||
|
||||
void readPacket( unsigned oldestEntry, uint64_t packetLogicalOffset );
|
||||
@@ -70,7 +71,7 @@ namespace e57
|
||||
struct CacheEntry
|
||||
{
|
||||
uint64_t logicalOffset_ = 0;
|
||||
char buffer_[DATA_PACKET_MAX]; //! No need to init since it's a data buffer
|
||||
char buffer_[DATA_PACKET_MAX]; // No need to init since it's a data buffer
|
||||
unsigned lastUsed_ = 0;
|
||||
};
|
||||
|
||||
@@ -86,13 +87,12 @@ namespace e57
|
||||
public:
|
||||
~PacketLock();
|
||||
|
||||
private:
|
||||
/// Can't be copied or assigned
|
||||
PacketLock( const PacketLock &plock );
|
||||
PacketLock &operator=( const PacketLock &plock );
|
||||
PacketLock( const PacketLock &plock ) = delete;
|
||||
PacketLock &operator=( const PacketLock &plock ) = delete;
|
||||
|
||||
protected:
|
||||
friend class PacketReadCache;
|
||||
|
||||
/// Only PacketReadCache can construct
|
||||
PacketLock( PacketReadCache *cache, unsigned cacheIndex );
|
||||
|
||||
@@ -107,11 +107,20 @@ namespace e57
|
||||
|
||||
void reset();
|
||||
|
||||
void verify( unsigned bufferLength = 0 ) const; //???use
|
||||
void verify( unsigned bufferLength = 0 ) const;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
// Does this packet have any records?
|
||||
bool hasRecords() const
|
||||
{
|
||||
// If the packet does not have records, the logical length will be 8 bytes (the length of
|
||||
// the header padded to 8-byte boundary).
|
||||
return packetLogicalLengthMinus1 > 7;
|
||||
}
|
||||
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
|
||||
const uint8_t packetType = DATA_PACKET;
|
||||
|
||||
uint8_t packetFlags = 0;
|
||||
@@ -128,7 +137,7 @@ namespace e57
|
||||
char *getBytestream( unsigned bytestreamNumber, unsigned &byteCount );
|
||||
unsigned getBytestreamBufferLength( unsigned bytestreamNumber );
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
|
||||
@@ -136,6 +145,41 @@ namespace e57
|
||||
|
||||
DataPacketHeader header;
|
||||
|
||||
uint8_t payload[PayloadSize]; //! No need to init since it's a data buffer
|
||||
uint8_t payload[PayloadSize]; // No need to init since it's a data buffer
|
||||
};
|
||||
|
||||
class IndexPacketHeader
|
||||
{
|
||||
public:
|
||||
const uint8_t packetType = INDEX_PACKET;
|
||||
|
||||
uint8_t packetFlags = 0; // flag bitfields
|
||||
uint16_t packetLogicalLengthMinus1 = 0;
|
||||
uint16_t entryCount = 0;
|
||||
uint8_t indexLevel = 0;
|
||||
uint8_t reserved1[9] = {}; // must be zero
|
||||
};
|
||||
|
||||
class IndexPacket
|
||||
{
|
||||
public:
|
||||
IndexPacket();
|
||||
|
||||
void verify( unsigned bufferLength = 0, uint64_t totalRecordCount = 0,
|
||||
uint64_t fileSize = 0 ) const;
|
||||
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
|
||||
IndexPacketHeader header;
|
||||
|
||||
static constexpr unsigned MAX_ENTRIES = 2048;
|
||||
|
||||
struct Entry
|
||||
{
|
||||
uint64_t chunkRecordNumber = 0;
|
||||
uint64_t chunkPhysicalOffset = 0;
|
||||
} entries[MAX_ENTRIES];
|
||||
};
|
||||
}
|
||||
|
||||
1550
src/3rdParty/libE57Format/src/ReaderImpl.cpp
vendored
1550
src/3rdParty/libE57Format/src/ReaderImpl.cpp
vendored
File diff suppressed because it is too large
Load Diff
56
src/3rdParty/libE57Format/src/ReaderImpl.h
vendored
56
src/3rdParty/libE57Format/src/ReaderImpl.h
vendored
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
|
||||
* Copyright (c) 2020 PTC Inc.
|
||||
* Copyright (c) 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
@@ -28,18 +29,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "E57SimpleData.h"
|
||||
#include "E57SimpleReader.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
|
||||
//! most of the functions follows Reader
|
||||
class ReaderImpl
|
||||
{
|
||||
public:
|
||||
ReaderImpl( const ustring &filePath );
|
||||
|
||||
ReaderImpl( const ustring &filePath, const ReaderOptions &options );
|
||||
~ReaderImpl();
|
||||
|
||||
// disallow copying a ReaderImpl
|
||||
ReaderImpl( const ReaderImpl & ) = delete;
|
||||
ReaderImpl &operator=( ReaderImpl const & ) = delete;
|
||||
ReaderImpl( const ReaderImpl && ) = delete;
|
||||
ReaderImpl &operator=( const ReaderImpl && ) = delete;
|
||||
|
||||
bool IsOpen() const;
|
||||
|
||||
bool Close();
|
||||
@@ -50,26 +55,29 @@ namespace e57
|
||||
|
||||
bool ReadImage2D( int64_t imageIndex, Image2D &Image2DHeader ) const;
|
||||
|
||||
bool GetImage2DSizes( int64_t imageIndex, Image2DProjection &imageProjection, Image2DType &imageType,
|
||||
int64_t &imageWidth, int64_t &imageHeight, int64_t &imageSize, Image2DType &imageMaskType,
|
||||
bool GetImage2DSizes( int64_t imageIndex, Image2DProjection &imageProjection,
|
||||
Image2DType &imageType, int64_t &imageWidth, int64_t &imageHeight,
|
||||
int64_t &imageSize, Image2DType &imageMaskType,
|
||||
Image2DType &imageVisualType ) const;
|
||||
|
||||
int64_t ReadImage2DData( int64_t imageIndex, Image2DProjection imageProjection, Image2DType imageType,
|
||||
void *pBuffer, int64_t start, int64_t count ) const;
|
||||
size_t ReadImage2DData( int64_t imageIndex, Image2DProjection imageProjection,
|
||||
Image2DType imageType, uint8_t *pBuffer, int64_t start,
|
||||
size_t count ) const;
|
||||
|
||||
int64_t GetData3DCount() const;
|
||||
|
||||
bool ReadData3D( int64_t dataIndex, Data3D &data3DHeader ) const;
|
||||
|
||||
bool GetData3DSizes( int64_t dataIndex, int64_t &rowMax, int64_t &columnMax, int64_t &pointsSize,
|
||||
int64_t &groupsSize, int64_t &countSize, bool &bColumnIndex ) const;
|
||||
bool GetData3DSizes( int64_t dataIndex, int64_t &rowMax, int64_t &columnMax,
|
||||
int64_t &pointsSize, int64_t &groupsSize, int64_t &countSize,
|
||||
bool &bColumnIndex ) const;
|
||||
|
||||
bool ReadData3DGroupsData( int64_t dataIndex, int64_t groupCount, int64_t *idElementValue,
|
||||
bool ReadData3DGroupsData( int64_t dataIndex, size_t groupCount, int64_t *idElementValue,
|
||||
int64_t *startPointIndex, int64_t *pointCount ) const;
|
||||
|
||||
template <typename COORDTYPE>
|
||||
CompressedVectorReader SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsData_t<COORDTYPE> &buffers ) const;
|
||||
CompressedVectorReader SetUpData3DPointsData(
|
||||
int64_t dataIndex, size_t pointCount, const Data3DPointsData_t<COORDTYPE> &buffers ) const;
|
||||
|
||||
StructureNode GetRawE57Root() const;
|
||||
|
||||
@@ -86,27 +94,5 @@ namespace e57
|
||||
VectorNode data3D_;
|
||||
|
||||
VectorNode images2D_;
|
||||
|
||||
//! @brief This function reads one of the image blobs
|
||||
//! @param [in] image 1 of 3 projects or the visual
|
||||
//! @param [out] imageType identifies the image format desired.
|
||||
//! @param [out] imageWidth The image width (in pixels).
|
||||
//! @param [out] imageHeight The image height (in pixels).
|
||||
//! @param [out] imageSize This is the total number of bytes for the image blob.
|
||||
//! @param [out] imageMaskType This is E57_PNG_IMAGE_MASK if "imageMask" is defined in the projection
|
||||
//! @return Returns true if successful
|
||||
bool GetImage2DNodeSizes( StructureNode image, Image2DType &imageType, int64_t &imageWidth, int64_t &imageHeight,
|
||||
int64_t &imageSize, Image2DType &imageMaskType ) const;
|
||||
|
||||
//! @brief Reads the data out of a given image node
|
||||
//! @param [in] image 1 of 3 projects or the visual
|
||||
//! @param [in] imageType identifies the image format desired.
|
||||
//! @param [out] pBuffer pointer the buffer
|
||||
//! @param [out] start position in the block to start reading
|
||||
//! @param [out] count size of desired chuck or buffer size
|
||||
//! @return number of bytes read
|
||||
int64_t ReadImage2DNode( StructureNode image, Image2DType imageType, void *pBuffer, int64_t start,
|
||||
int64_t count ) const;
|
||||
}; // end Reader class
|
||||
|
||||
} // end namespace e57
|
||||
|
||||
485
src/3rdParty/libE57Format/src/ScaledIntegerNode.cpp
vendored
Normal file
485
src/3rdParty/libE57Format/src/ScaledIntegerNode.cpp
vendored
Normal file
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* ScaledIntegerNode.cpp - implementation of public functions of the ScaledIntegerNode class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file ScaledIntegerNode.cpp
|
||||
|
||||
#include "ScaledIntegerNodeImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether ScaledIntegerNode class invariant is true
|
||||
@copydetails IntegerNode::checkInvariant()
|
||||
*/
|
||||
void ScaledIntegerNode::checkInvariant( bool /*doRecurse*/, bool doUpcast ) const
|
||||
{
|
||||
// If destImageFile not open, can't test invariant (almost every call would throw)
|
||||
if ( !destImageFile().isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If requested, call Node::checkInvariant
|
||||
if ( doUpcast )
|
||||
{
|
||||
static_cast<Node>( *this ).checkInvariant( false, false );
|
||||
}
|
||||
|
||||
// If value is out of bounds
|
||||
if ( rawValue() < minimum() || rawValue() > maximum() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// If scale is zero
|
||||
if ( scale() == 0 )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// If scaled value is not calculated correctly
|
||||
if ( scaledValue() != rawValue() * scale() + offset() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::ScaledIntegerNode
|
||||
|
||||
@brief An E57 element encoding a fixed point number.
|
||||
|
||||
@details
|
||||
An ScaledIntegerNode is a terminal node (i.e. having no children) that holds a fixed point number
|
||||
encoded by an integer @c rawValue, a double precision floating point @c scale, an double precision
|
||||
floating point @c offset, and integer minimum/maximum bounds.
|
||||
|
||||
The @c minimum attribute may be a number in the interval [-2^63, 2^63).
|
||||
|
||||
The @c maximum attribute may be a number in the interval [minimum, 2^63).
|
||||
|
||||
The @c rawValue may be a number in the interval [minimum, maximum].
|
||||
|
||||
The @c scaledValue is a calculated double precision floating point number derived from: scaledValue
|
||||
= rawValue*scale + offset.
|
||||
|
||||
See Node class discussion for discussion of the common functions that StructureNode supports.
|
||||
|
||||
@section ScaledIntegerNode_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude ScaledIntegerNode.cpp
|
||||
@skip void ScaledIntegerNode::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see Node
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Create an E57 element for storing a fixed point number.
|
||||
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
@param [in] rawValue The raw integer value of the element.
|
||||
@param [in] minimum The smallest rawValue that the element may take.
|
||||
@param [in] maximum The largest rawValue that the element may take.
|
||||
@param [in] scale The scaling factor used to compute scaledValue from rawValue.
|
||||
@param [in] offset The offset factor used to compute scaledValue from rawValue.
|
||||
|
||||
@details
|
||||
A ScaledIntegerNode stores an integer value, a lower and upper bound, and two conversion factors.
|
||||
The ScaledIntegerNode class corresponds to the ASTM E57 standard ScaledInteger element. See the
|
||||
class discussion at bottom of ScaledIntegerNode page for more details.
|
||||
|
||||
The @a destImageFile indicates which ImageFile the ScaledIntegerNode will eventually be attached to.
|
||||
A node is attached to an ImageFile by adding it underneath the predefined root of the ImageFile
|
||||
(gotten from ImageFile::root). It is not an error to fail to attach the ScaledIntegerNode to the @a
|
||||
destImageFile. It is an error to attempt to attach the ScaledIntegerNode to a different ImageFile.
|
||||
|
||||
@warning It is an error to give an @a rawValue outside the @a minimum / @a maximum bounds, even if
|
||||
the ScaledIntegerNode is destined to be used in a CompressedVectorNode prototype (where the @a
|
||||
rawValue will be ignored). If the ScaledIntegerNode is to be used in a prototype, it is recommended
|
||||
to specify a @a rawValue = 0 if 0 is within bounds, or a @a rawValue = @a minimum if 0 is not within
|
||||
bounds.
|
||||
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
@pre minimum <= rawValue <= maximum
|
||||
@pre scale != 0
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorValueOutOfBounds
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::rawValue, Node, CompressedVectorNode, CompressedVectorNode::prototype
|
||||
*/
|
||||
ScaledIntegerNode::ScaledIntegerNode( const ImageFile &destImageFile, int64_t rawValue,
|
||||
int64_t minimum, int64_t maximum, double scale,
|
||||
double offset ) :
|
||||
impl_(
|
||||
new ScaledIntegerNodeImpl( destImageFile.impl(), rawValue, minimum, maximum, scale, offset ) )
|
||||
{
|
||||
impl_->validateValue();
|
||||
}
|
||||
|
||||
ScaledIntegerNode::ScaledIntegerNode( const ImageFile &destImageFile, int rawValue, int64_t minimum,
|
||||
int64_t maximum, double scale, double offset ) :
|
||||
impl_( new ScaledIntegerNodeImpl( destImageFile.impl(), static_cast<int64_t>( rawValue ),
|
||||
minimum, maximum, scale, offset ) )
|
||||
{
|
||||
impl_->validateValue();
|
||||
}
|
||||
|
||||
ScaledIntegerNode::ScaledIntegerNode( const ImageFile &destImageFile, int rawValue, int minimum,
|
||||
int maximum, double scale, double offset ) :
|
||||
impl_( new ScaledIntegerNodeImpl( destImageFile.impl(), static_cast<int64_t>( rawValue ),
|
||||
static_cast<int64_t>( minimum ),
|
||||
static_cast<int64_t>( maximum ), scale, offset ) )
|
||||
{
|
||||
impl_->validateValue();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief This second constructor creates an E57 element for storing a fixed point number but does the
|
||||
scaling for you.
|
||||
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
@param [in] scaledValue The scaled integer value of the element.
|
||||
@param [in] scaledMinimum The smallest scaledValue that the element may take.
|
||||
@param [in] scaledMaximum The largest scaledValue that the element may take.
|
||||
@param [in] scale The scaling factor used to compute scaledValue from rawValue.
|
||||
@param [in] offset The offset factor used to compute scaledValue from rawValue.
|
||||
|
||||
@details
|
||||
A ScaledIntegerNode stores an integer value, a lower and upper bound, and two conversion factors.
|
||||
This ScaledIntegerNode constructor calculates the rawValue, minimum, and maximum by doing the
|
||||
floor((scaledValue - offset)/scale + .5) on each scaled parameters.
|
||||
|
||||
@warning It is an error to give an @a rawValue outside the @a minimum / @a maximum bounds, even if
|
||||
the ScaledIntegerNode is destined to be used in a CompressedVectorNode prototype (where the @a
|
||||
rawValue will be ignored). If the ScaledIntegerNode is to be used in a prototype, it is recommended
|
||||
to specify a @a rawValue = 0 if 0 is within bounds, or a @a rawValue = @a minimum if 0 is not within
|
||||
bounds.
|
||||
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
@pre scaledMinimum <= scaledValue <= scaledMaximum
|
||||
@pre scale != 0
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorValueOutOfBounds
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledValue, Node, CompressedVectorNode, CompressedVectorNode::prototype
|
||||
*/
|
||||
ScaledIntegerNode::ScaledIntegerNode( const ImageFile &destImageFile, double scaledValue,
|
||||
double scaledMinimum, double scaledMaximum, double scale,
|
||||
double offset ) :
|
||||
impl_( new ScaledIntegerNodeImpl( destImageFile.impl(), scaledValue, scaledMinimum,
|
||||
scaledMaximum, scale, offset ) )
|
||||
{
|
||||
impl_->validateValue();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is this a root node.
|
||||
@copydetails Node::isRoot()
|
||||
*/
|
||||
bool ScaledIntegerNode::isRoot() const
|
||||
{
|
||||
return impl_->isRoot();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return parent of node, or self if a root node.
|
||||
@copydetails Node::parent()
|
||||
*/
|
||||
Node ScaledIntegerNode::parent() const
|
||||
{
|
||||
return Node( impl_->parent() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get absolute pathname of node.
|
||||
@copydetails Node::pathName()
|
||||
*/
|
||||
ustring ScaledIntegerNode::pathName() const
|
||||
{
|
||||
return impl_->pathName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get elementName string, that identifies the node in its parent.
|
||||
@copydetails Node::elementName()
|
||||
*/
|
||||
ustring ScaledIntegerNode::elementName() const
|
||||
{
|
||||
return impl_->elementName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the ImageFile that was declared as the destination for the node when it was created.
|
||||
@copydetails Node::destImageFile()
|
||||
*/
|
||||
ImageFile ScaledIntegerNode::destImageFile() const
|
||||
{
|
||||
return ImageFile( impl_->destImageFile() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Has node been attached into the tree of an ImageFile.
|
||||
@copydetails Node::isAttached()
|
||||
*/
|
||||
bool ScaledIntegerNode::isAttached() const
|
||||
{
|
||||
return impl_->isAttached();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get raw unscaled integer value of element.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The raw unscaled integer value stored.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledValue, ScaledIntegerNode::minimum, ScaledIntegerNode::maximum
|
||||
*/
|
||||
int64_t ScaledIntegerNode::rawValue() const
|
||||
{
|
||||
return impl_->rawValue();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get scaled value of element.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The scaled value (rawValue*scale + offset) calculated from the rawValue stored.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::rawValue
|
||||
*/
|
||||
double ScaledIntegerNode::scaledValue() const
|
||||
{
|
||||
return impl_->scaledValue();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the declared minimum that the raw value may take.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The declared minimum that the rawValue may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::maximum, ScaledIntegerNode::rawValue
|
||||
*/
|
||||
int64_t ScaledIntegerNode::minimum() const
|
||||
{
|
||||
return impl_->minimum();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the declared scaled minimum that the scaled value may take.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The declared minimum that the rawValue may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledMaximum, ScaledIntegerNode::scaledValue
|
||||
*/
|
||||
double ScaledIntegerNode::scaledMinimum() const
|
||||
{
|
||||
return impl_->scaledMinimum();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the declared maximum that the raw value may take.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The declared maximum that the rawValue may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::minimum, ScaledIntegerNode::rawValue
|
||||
*/
|
||||
int64_t ScaledIntegerNode::maximum() const
|
||||
{
|
||||
return impl_->maximum();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the declared scaled maximum that the scaled value may take.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The declared maximum that the rawValue may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledMinimum, ScaledIntegerNode::scaledValue
|
||||
*/
|
||||
double ScaledIntegerNode::scaledMaximum() const // Added by SC
|
||||
{
|
||||
return impl_->scaledMaximum();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get declared scaling factor.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The scaling factor used to compute scaledValue from rawValue.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledValue
|
||||
*/
|
||||
double ScaledIntegerNode::scale() const
|
||||
{
|
||||
return impl_->scale();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get declared offset.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The offset used to compute scaledValue from rawValue.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledValue
|
||||
*/
|
||||
double ScaledIntegerNode::offset() const
|
||||
{
|
||||
return impl_->offset();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void ScaledIntegerNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void ScaledIntegerNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Upcast a ScaledIntegerNode handle to a generic Node handle.
|
||||
|
||||
@details
|
||||
An upcast is always safe, and the compiler can automatically insert it for initializations of Node
|
||||
variables and Node function arguments.
|
||||
|
||||
@return A smart Node handle referencing the underlying object.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see Explanation in Node, Node::type(), ScaledIntegerNode(const Node&)
|
||||
*/
|
||||
ScaledIntegerNode::operator Node() const
|
||||
{
|
||||
// Upcast from shared_ptr<ScaledIntegerNodeImpl> to SharedNodeImplPtr and construct a Node object
|
||||
return Node( impl_ );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Downcast a generic Node handle to an ScaledIntegerNode handle.
|
||||
|
||||
@param [in] n The generic handle to downcast.
|
||||
|
||||
@details
|
||||
The handle @a n must be for an underlying ScaledIntegerNode, otherwise an exception is thrown. In
|
||||
designs that need to avoid the exception, use Node::type() to determine the actual type of the @a n
|
||||
before downcasting. This function must be explicitly called (c++ compiler cannot insert it
|
||||
automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
|
||||
@see Node::type(), ScaledIntegerNode::operator, Node()
|
||||
*/
|
||||
ScaledIntegerNode::ScaledIntegerNode( const Node &n )
|
||||
{
|
||||
if ( n.type() != TypeScaledInteger )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadNodeDowncast, "nodeType=" + toString( n.type() ) );
|
||||
}
|
||||
|
||||
// Set our shared_ptr to the downcast shared_ptr
|
||||
impl_ = std::static_pointer_cast<ScaledIntegerNodeImpl>( n.impl() );
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
ScaledIntegerNode::ScaledIntegerNode( std::shared_ptr<ScaledIntegerNodeImpl> ni ) : impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
@@ -29,43 +29,39 @@
|
||||
|
||||
#include "CheckedFile.h"
|
||||
#include "ScaledIntegerNodeImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
ScaledIntegerNodeImpl::ScaledIntegerNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t rawValue, int64_t minimum,
|
||||
int64_t maximum, double scale, double offset ) :
|
||||
NodeImpl( destImageFile ),
|
||||
value_( rawValue ), minimum_( minimum ), maximum_( maximum ), scale_( scale ), offset_( offset )
|
||||
ScaledIntegerNodeImpl::ScaledIntegerNodeImpl( ImageFileImplWeakPtr destImageFile,
|
||||
int64_t rawValue, int64_t minimum, int64_t maximum,
|
||||
double scale, double offset ) :
|
||||
NodeImpl( destImageFile ), value_( rawValue ), minimum_( minimum ), maximum_( maximum ),
|
||||
scale_( scale ), offset_( offset )
|
||||
{
|
||||
// don't checkImageFileOpen, NodeImpl() will do it
|
||||
|
||||
/// Enforce the given bounds on raw value
|
||||
if ( rawValue < minimum || maximum < rawValue )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_VALUE_OUT_OF_BOUNDS,
|
||||
"this->pathName=" + this->pathName() + " rawValue=" + toString( rawValue ) +
|
||||
" minimum=" + toString( minimum ) + " maximum=" + toString( maximum ) );
|
||||
}
|
||||
}
|
||||
|
||||
ScaledIntegerNodeImpl::ScaledIntegerNodeImpl( ImageFileImplWeakPtr destImageFile, double scaledValue,
|
||||
double scaledMinimum, double scaledMaximum, double scale,
|
||||
ScaledIntegerNodeImpl::ScaledIntegerNodeImpl( ImageFileImplWeakPtr destImageFile,
|
||||
double scaledValue, double scaledMinimum,
|
||||
double scaledMaximum, double scale,
|
||||
double offset ) :
|
||||
NodeImpl( destImageFile ),
|
||||
value_( static_cast<int64_t>( std::floor( ( scaledValue - offset ) / scale + .5 ) ) ),
|
||||
minimum_( static_cast<int64_t>( std::floor( ( scaledMinimum - offset ) / scale + .5 ) ) ),
|
||||
maximum_( static_cast<int64_t>( std::floor( ( scaledMaximum - offset ) / scale + .5 ) ) ), scale_( scale ),
|
||||
offset_( offset )
|
||||
maximum_( static_cast<int64_t>( std::floor( ( scaledMaximum - offset ) / scale + .5 ) ) ),
|
||||
scale_( scale ), offset_( offset )
|
||||
{
|
||||
// don't checkImageFileOpen, NodeImpl() will do it
|
||||
}
|
||||
|
||||
/// Enforce the given bounds on raw value
|
||||
if ( scaledValue < scaledMinimum || scaledMaximum < scaledValue )
|
||||
// Throw an exception if the value is not within bounds.
|
||||
void ScaledIntegerNodeImpl::validateValue() const
|
||||
{
|
||||
if ( value_ < minimum_ || value_ > maximum_ )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_VALUE_OUT_OF_BOUNDS, "this->pathName=" + this->pathName() +
|
||||
" scaledValue=" + toString( scaledValue ) +
|
||||
" scaledMinimum=" + toString( scaledMinimum ) +
|
||||
" scaledMaximum=" + toString( scaledMaximum ) );
|
||||
throw E57_EXCEPTION2( ErrorValueOutOfBounds, "this->pathName=" + this->pathName() +
|
||||
" value=" + toString( value_ ) +
|
||||
" minimum=" + toString( minimum_ ) +
|
||||
" maximum=" + toString( maximum_ ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,42 +69,43 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// Same node type?
|
||||
if ( ni->type() != E57_SCALED_INTEGER )
|
||||
// Same node type?
|
||||
if ( ni->type() != TypeScaledInteger )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// Downcast to shared_ptr<ScaledIntegerNodeImpl>
|
||||
std::shared_ptr<ScaledIntegerNodeImpl> ii( std::static_pointer_cast<ScaledIntegerNodeImpl>( ni ) );
|
||||
// Downcast to shared_ptr<ScaledIntegerNodeImpl>
|
||||
std::shared_ptr<ScaledIntegerNodeImpl> ii(
|
||||
std::static_pointer_cast<ScaledIntegerNodeImpl>( ni ) );
|
||||
|
||||
/// minimum must match
|
||||
// minimum must match
|
||||
if ( minimum_ != ii->minimum_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// maximum must match
|
||||
// maximum must match
|
||||
if ( maximum_ != ii->maximum_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// scale must match
|
||||
// scale must match
|
||||
if ( scale_ != ii->scale_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// offset must match
|
||||
// offset must match
|
||||
if ( offset_ != ii->offset_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// ignore value_, doesn't have to match
|
||||
// ignore value_, doesn't have to match
|
||||
|
||||
/// Types match
|
||||
// Types match
|
||||
return ( true );
|
||||
}
|
||||
|
||||
@@ -116,7 +113,7 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// We have no sub-structure, so if path not empty return false
|
||||
// We have no sub-structure, so if path not empty return false
|
||||
return pathName.empty();
|
||||
}
|
||||
|
||||
@@ -137,6 +134,7 @@ namespace e57
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
return ( minimum_ );
|
||||
}
|
||||
|
||||
double ScaledIntegerNodeImpl::scaledMinimum()
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
@@ -148,6 +146,7 @@ namespace e57
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
return ( maximum_ );
|
||||
}
|
||||
|
||||
double ScaledIntegerNodeImpl::scaledMaximum()
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
@@ -166,24 +165,25 @@ namespace e57
|
||||
return ( offset_ );
|
||||
}
|
||||
|
||||
void ScaledIntegerNodeImpl::checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin )
|
||||
void ScaledIntegerNodeImpl::checkLeavesInSet( const StringSet &pathNames,
|
||||
NodeImplSharedPtr origin )
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// We are a leaf node, so verify that we are listed in set.
|
||||
// We are a leaf node, so verify that we are listed in set.
|
||||
if ( pathNames.find( relativePathName( origin ) ) == pathNames.end() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_NO_BUFFER_FOR_ELEMENT, "this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorNoBufferForElement, "this->pathName=" + this->pathName() );
|
||||
}
|
||||
}
|
||||
|
||||
void ScaledIntegerNodeImpl::writeXml( ImageFileImplSharedPtr /*imf*/, CheckedFile &cf, int indent,
|
||||
const char *forcedFieldName )
|
||||
void ScaledIntegerNodeImpl::writeXml( ImageFileImplSharedPtr /*imf*/, CheckedFile &cf,
|
||||
int indent, const char *forcedFieldName )
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
ustring fieldName;
|
||||
if ( forcedFieldName )
|
||||
if ( forcedFieldName != nullptr )
|
||||
{
|
||||
fieldName = forcedFieldName;
|
||||
}
|
||||
@@ -194,12 +194,12 @@ namespace e57
|
||||
|
||||
cf << space( indent ) << "<" << fieldName << " type=\"ScaledInteger\"";
|
||||
|
||||
/// Don't need to write if are default values
|
||||
if ( minimum_ != E57_INT64_MIN )
|
||||
// Don't need to write if are default values
|
||||
if ( minimum_ != INT64_MIN )
|
||||
{
|
||||
cf << " minimum=\"" << minimum_ << "\"";
|
||||
}
|
||||
if ( maximum_ != E57_INT64_MAX )
|
||||
if ( maximum_ != INT64_MAX )
|
||||
{
|
||||
cf << " maximum=\"" << maximum_ << "\"";
|
||||
}
|
||||
@@ -212,7 +212,7 @@ namespace e57
|
||||
cf << " offset=\"" << offset_ << "\"";
|
||||
}
|
||||
|
||||
/// Write value as child text, unless it is the default value
|
||||
// Write value as child text, unless it is the default value
|
||||
if ( value_ != 0 )
|
||||
{
|
||||
cf << ">" << value_ << "</" << fieldName << ">\n";
|
||||
@@ -223,12 +223,11 @@ namespace e57
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void ScaledIntegerNodeImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
os << space( indent ) << "type: ScaledInteger"
|
||||
<< " (" << type() << ")" << std::endl;
|
||||
os << space( indent ) << "type: ScaledInteger" << " (" << type() << ")" << std::endl;
|
||||
NodeImpl::dump( indent, os );
|
||||
os << space( indent ) << "rawValue: " << value_ << std::endl;
|
||||
os << space( indent ) << "minimum: " << minimum_ << std::endl;
|
||||
|
||||
@@ -33,18 +33,22 @@ namespace e57
|
||||
class ScaledIntegerNodeImpl : public NodeImpl
|
||||
{
|
||||
public:
|
||||
ScaledIntegerNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t value = 0, int64_t minimum = 0,
|
||||
int64_t maximum = 0, double scale = 1.0, double offset = 0.0 );
|
||||
ScaledIntegerNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t value, int64_t minimum,
|
||||
int64_t maximum, double scale, double offset );
|
||||
|
||||
ScaledIntegerNodeImpl( ImageFileImplWeakPtr destImageFile, double scaledValue = 0., double scaledMinimum = 0.,
|
||||
double scaledMaximum = 0., double scale = 1.0, double offset = 0.0 );
|
||||
ScaledIntegerNodeImpl( ImageFileImplWeakPtr destImageFile, double scaledValue,
|
||||
double scaledMinimum, double scaledMaximum, double scale,
|
||||
double offset );
|
||||
|
||||
~ScaledIntegerNodeImpl() override = default;
|
||||
|
||||
NodeType type() const override
|
||||
{
|
||||
return E57_SCALED_INTEGER;
|
||||
return TypeScaledInteger;
|
||||
}
|
||||
|
||||
void validateValue() const;
|
||||
|
||||
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
|
||||
bool isDefined( const ustring &pathName ) override;
|
||||
|
||||
@@ -62,7 +66,7 @@ namespace e57
|
||||
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
|
||||
const char *forcedFieldName = nullptr ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
|
||||
53
src/3rdParty/libE57Format/src/SectionHeaders.cpp
vendored
53
src/3rdParty/libE57Format/src/SectionHeaders.cpp
vendored
@@ -26,11 +26,12 @@
|
||||
*/
|
||||
|
||||
#include "SectionHeaders.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
#ifdef E57_DEBUG
|
||||
void BlobSectionHeader::dump( int indent, std::ostream &os )
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void BlobSectionHeader::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
os << space( indent ) << "sectionId: " << sectionId << std::endl;
|
||||
os << space( indent ) << "sectionLogicalLength: " << sectionLogicalLength << std::endl;
|
||||
@@ -39,56 +40,70 @@ namespace e57
|
||||
|
||||
CompressedVectorSectionHeader::CompressedVectorSectionHeader()
|
||||
{
|
||||
/// Double check that header is correct length. Watch out for RTTI
|
||||
/// increasing the size.
|
||||
// Double check that header is correct length. Watch out for RTTI increasing the size.
|
||||
static_assert( sizeof( CompressedVectorSectionHeader ) == 32,
|
||||
"Unexpected size of CompressedVectorSectionHeader" );
|
||||
}
|
||||
|
||||
void CompressedVectorSectionHeader::verify( uint64_t filePhysicalSize )
|
||||
{
|
||||
/// Verify reserved fields are zero. ??? if fileversion==1.0 ???
|
||||
// Verify section ID is 1
|
||||
// cppcheck-suppress knownConditionTrueFalse; (data is read as a blob, so the const might not
|
||||
// be valid)
|
||||
if ( sectionId != COMPRESSED_VECTOR_SECTION )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadCVHeader,
|
||||
"sectionId=" + toString( static_cast<int>( sectionId ) ) +
|
||||
" (expected 1)" );
|
||||
}
|
||||
|
||||
// Verify reserved fields are zero. ??? if fileversion==1.0 ???
|
||||
for ( unsigned i = 0; i < sizeof( reserved1 ); i++ )
|
||||
{
|
||||
if ( reserved1[i] != 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_HEADER,
|
||||
throw E57_EXCEPTION2( ErrorBadCVHeader,
|
||||
"i=" + toString( i ) + " reserved=" + toString( reserved1[i] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/// Check section length is multiple of 4
|
||||
// Check section length is multiple of 4
|
||||
if ( sectionLogicalLength % 4 )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_HEADER, "sectionLogicalLength=" + toString( sectionLogicalLength ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVHeader,
|
||||
"sectionLogicalLength=" + toString( sectionLogicalLength ) );
|
||||
}
|
||||
|
||||
/// Check sectionLogicalLength is in bounds
|
||||
// Check sectionLogicalLength is in bounds
|
||||
if ( filePhysicalSize > 0 && sectionLogicalLength >= filePhysicalSize )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_HEADER, "sectionLogicalLength=" + toString( sectionLogicalLength ) +
|
||||
" filePhysicalSize=" + toString( filePhysicalSize ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVHeader,
|
||||
"sectionLogicalLength=" + toString( sectionLogicalLength ) +
|
||||
" filePhysicalSize=" + toString( filePhysicalSize ) );
|
||||
}
|
||||
|
||||
/// Check dataPhysicalOffset is in bounds
|
||||
// Check dataPhysicalOffset is in bounds
|
||||
if ( filePhysicalSize > 0 && dataPhysicalOffset >= filePhysicalSize )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_HEADER, "dataPhysicalOffset=" + toString( dataPhysicalOffset ) +
|
||||
" filePhysicalSize=" + toString( filePhysicalSize ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVHeader,
|
||||
"dataPhysicalOffset=" + toString( dataPhysicalOffset ) +
|
||||
" filePhysicalSize=" + toString( filePhysicalSize ) );
|
||||
}
|
||||
|
||||
/// Check indexPhysicalOffset is in bounds
|
||||
// Check indexPhysicalOffset is in bounds
|
||||
if ( filePhysicalSize > 0 && indexPhysicalOffset >= filePhysicalSize )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_HEADER, "indexPhysicalOffset=" + toString( indexPhysicalOffset ) +
|
||||
" filePhysicalSize=" + toString( filePhysicalSize ) );
|
||||
throw E57_EXCEPTION2( ErrorBadCVHeader,
|
||||
"indexPhysicalOffset=" + toString( indexPhysicalOffset ) +
|
||||
" filePhysicalSize=" + toString( filePhysicalSize ) );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void CompressedVectorSectionHeader::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
os << space( indent ) << "sectionId: " << static_cast<unsigned>( sectionId ) << std::endl;
|
||||
os << space( indent ) << "sectionId: " << static_cast<unsigned>( sectionId )
|
||||
<< std::endl;
|
||||
os << space( indent ) << "sectionLogicalLength: " << sectionLogicalLength << std::endl;
|
||||
os << space( indent ) << "dataPhysicalOffset: " << dataPhysicalOffset << std::endl;
|
||||
os << space( indent ) << "indexPhysicalOffset: " << indexPhysicalOffset << std::endl;
|
||||
|
||||
@@ -43,8 +43,8 @@ namespace e57
|
||||
uint8_t reserved1[7] = {}; // must be zero
|
||||
uint64_t sectionLogicalLength = 0; // byte length of whole section
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
void dump( int indent = 0, std::ostream &os = std::cout );
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -58,9 +58,10 @@ namespace e57
|
||||
uint64_t indexPhysicalOffset = 0; // offset of first index packet
|
||||
|
||||
CompressedVectorSectionHeader();
|
||||
|
||||
void verify( uint64_t filePhysicalSize = 0 );
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
478
src/3rdParty/libE57Format/src/SourceDestBuffer.cpp
vendored
Normal file
478
src/3rdParty/libE57Format/src/SourceDestBuffer.cpp
vendored
Normal file
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* SourceDestBuffer.cpp - implementation of public functions of the SourceDestBuffer class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file SourceDestBuffer.cpp
|
||||
|
||||
#include "SourceDestBufferImpl.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/// @brief Check whether SourceDestBuffer class invariant is true
|
||||
void SourceDestBuffer::checkInvariant( bool /*doRecurse*/ ) const
|
||||
{
|
||||
// Stride must be >= a memory type dependent value
|
||||
const size_t min_stride = []( MemoryRepresentation inRep ) -> size_t {
|
||||
switch ( inRep )
|
||||
{
|
||||
case Bool:
|
||||
case Int8:
|
||||
case UInt8:
|
||||
return 1;
|
||||
|
||||
case Int16:
|
||||
case UInt16:
|
||||
return 2;
|
||||
|
||||
case Int32:
|
||||
case UInt32:
|
||||
case Real32:
|
||||
return 4;
|
||||
|
||||
case Int64:
|
||||
case Real64:
|
||||
return 8;
|
||||
|
||||
case UString:
|
||||
return sizeof( ustring );
|
||||
|
||||
default:
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}( memoryRepresentation() );
|
||||
|
||||
if ( stride() < min_stride )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::SourceDestBuffer
|
||||
|
||||
@brief A memory buffer to transfer data to/from a CompressedVectorNode in a block.
|
||||
|
||||
@details
|
||||
The SourceDestBuffer is an encapsulation of a buffer in memory that will transfer data to/from a
|
||||
field in a CompressedVectorNode. The API user is responsible for creating the actual memory buffer,
|
||||
describing it correctly to the API, making sure it exists during the transfer period, and destroying
|
||||
it after the transfer is complete. Additionally, the SourceDestBuffer has information that specifies
|
||||
the connection to the CompressedVectorNode field (i.e. the field's path name in the prototype).
|
||||
|
||||
The type of buffer element may be an assortment of built-in C++ memory types. There are all
|
||||
combinations of signed/unsigned and 8/16/32/64 bit integers (except unsigned 64bit integer, which is
|
||||
not supported in the ASTM standard), bool, float, double, as well as a vector of variable length
|
||||
unicode strings. The compiler selects the appropriate constructor automatically based on the type of
|
||||
the buffer array. However, the API user is responsible for reporting the correct length and stride
|
||||
options (otherwise unspecified behavior can occur).
|
||||
|
||||
The connection of the SourceDestBuffer to a CompressedVectorNode field is established by specifying
|
||||
the pathName. There are several options to this connection: doConversion and doScaling, which are
|
||||
described in the constructor documentation.
|
||||
|
||||
@section sourcedestbuffer_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude SourceDestBuffer.cpp
|
||||
@skip void SourceDestBuffer::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see Node
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Designate buffers to transfer data to/from a CompressedVectorNode in a block.
|
||||
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
@param [in] pathName The pathname of the field in CompressedVectorNode that will transfer data
|
||||
to/from.
|
||||
@param [in] b The caller allocated memory buffer.
|
||||
@param [in] capacity The total number of memory elements in buffer @a b.
|
||||
@param [in] doConversion Will a conversion be attempted between memory and ImageFile
|
||||
representations.
|
||||
@param [in] doScaling In a ScaledInteger field, do memory elements hold scaled values, if false they
|
||||
hold raw values.
|
||||
@param [in] stride The number of bytes between memory elements. If zero, defaults to sizeof memory
|
||||
element.
|
||||
|
||||
@details
|
||||
This overloaded form of the SourceDestBuffer constructor declares a buffer @a b to be the
|
||||
source/destination of a transfer of values stored in a CompressedVectorNode.
|
||||
|
||||
The @a pathName will be used to identify a Node in the prototype that will get/receive data from
|
||||
this buffer. The @a pathName may be an absolute path name (e.g. "/cartesianX") or a path name
|
||||
relative to the root of the prototype (i.e. the absolute path name without the leading "/", for
|
||||
example: "cartesianX").
|
||||
|
||||
The type of @a b is used to determine the MemoryRepresentation of the SourceDestBuffer. The buffer
|
||||
@a b may be used for multiple block transfers. See discussions of operation of SourceDestBuffer
|
||||
attributes in SourceDestBuffer::memoryRepresentation, SourceDestBuffer::capacity,
|
||||
SourceDestBuffer::doConversion, and SourceDestBuffer::doScaling, and SourceDestBuffer::stride.
|
||||
|
||||
The API user is responsible for ensuring that the lifetime of the @a b memory buffer exceeds the
|
||||
time that it is used in transfers (i.e. the E57 Foundation Implementation cannot detect that the
|
||||
buffer been destroyed).
|
||||
|
||||
The @a capacity must match the capacity of all other SourceDestBuffers that will participate in a
|
||||
transfer with a CompressedVectorNode.
|
||||
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The stride must be >= sizeof(*b)
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorBadBuffer
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::reader, ImageFile::writer,
|
||||
CompressedVectorReader::read(std::vector<SourceDestBuffer>&),
|
||||
CompressedVectorWriter::write(std::vector<SourceDestBuffer>&)
|
||||
*/
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
int8_t *b, const size_t capacity, bool doConversion,
|
||||
bool doScaling, size_t stride ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, capacity, doConversion,
|
||||
doScaling ) )
|
||||
{
|
||||
impl_->setTypeInfo<int8_t>( b, stride );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
uint8_t *b, const size_t capacity, bool doConversion,
|
||||
bool doScaling, size_t stride ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, capacity, doConversion,
|
||||
doScaling ) )
|
||||
{
|
||||
impl_->setTypeInfo<uint8_t>( b, stride );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
int16_t *b, const size_t capacity, bool doConversion,
|
||||
bool doScaling, size_t stride ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, capacity, doConversion,
|
||||
doScaling ) )
|
||||
{
|
||||
impl_->setTypeInfo<int16_t>( b, stride );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
uint16_t *b, const size_t capacity, bool doConversion,
|
||||
bool doScaling, size_t stride ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, capacity, doConversion,
|
||||
doScaling ) )
|
||||
{
|
||||
impl_->setTypeInfo<uint16_t>( b, stride );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
int32_t *b, const size_t capacity, bool doConversion,
|
||||
bool doScaling, size_t stride ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, capacity, doConversion,
|
||||
doScaling ) )
|
||||
{
|
||||
impl_->setTypeInfo<int32_t>( b, stride );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
uint32_t *b, const size_t capacity, bool doConversion,
|
||||
bool doScaling, size_t stride ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, capacity, doConversion,
|
||||
doScaling ) )
|
||||
{
|
||||
impl_->setTypeInfo<uint32_t>( b, stride );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
int64_t *b, const size_t capacity, bool doConversion,
|
||||
bool doScaling, size_t stride ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, capacity, doConversion,
|
||||
doScaling ) )
|
||||
{
|
||||
impl_->setTypeInfo<int64_t>( b, stride );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
bool *b, const size_t capacity, bool doConversion,
|
||||
bool doScaling, size_t stride ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, capacity, doConversion,
|
||||
doScaling ) )
|
||||
{
|
||||
impl_->setTypeInfo<bool>( b, stride );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
float *b, const size_t capacity, bool doConversion,
|
||||
bool doScaling, size_t stride ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, capacity, doConversion,
|
||||
doScaling ) )
|
||||
{
|
||||
impl_->setTypeInfo<float>( b, stride );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
double *b, const size_t capacity, bool doConversion,
|
||||
bool doScaling, size_t stride ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, capacity, doConversion,
|
||||
doScaling ) )
|
||||
{
|
||||
impl_->setTypeInfo<double>( b, stride );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Designate vector of strings to transfer data to/from a CompressedVector as a block.
|
||||
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
@param [in] pathName The pathname of the field in CompressedVectorNode that will transfer data
|
||||
to/from.
|
||||
@param [in] b The caller created vector of ustrings to transfer from/to.
|
||||
|
||||
@details
|
||||
This overloaded form of the SourceDestBuffer constructor declares a vector<ustring> to be the
|
||||
source/destination of a transfer of StringNode values stored in a CompressedVectorNode.
|
||||
|
||||
The @a pathName will be used to identify a Node in the prototype that will get/receive data from
|
||||
this buffer. The @a pathName may be an absolute path name (e.g. "/cartesianX") or a path name
|
||||
relative to the root of the prototype (i.e. the absolute path name without the leading "/", for
|
||||
example: "cartesianX").
|
||||
|
||||
The @a b->size() must match capacity of all other SourceDestBuffers that will participate in a
|
||||
transfer with a CompressedVectorNode (string or any other type of buffer). In a read into the
|
||||
SourceDestBuffer, the previous contents of the strings in the vector are lost, and the memory space
|
||||
is potentially freed. The @a b->size() of the vector will not be changed. It is an error to request
|
||||
a read/write of more records that @a b->size() (just as it would be for buffers of integer types).
|
||||
The API user is responsible for ensuring that the lifetime of the @a b vector exceeds the time that
|
||||
it is used in transfers (i.e. the E57 Foundation Implementation cannot detect that the buffer been
|
||||
destroyed).
|
||||
|
||||
@pre b.size() must be > 0.
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorBadBuffer
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see SourceDestBuffer::doConversion for discussion on representations compatible with string
|
||||
SourceDestBuffers.
|
||||
*/
|
||||
SourceDestBuffer::SourceDestBuffer( const ImageFile &destImageFile, const ustring &pathName,
|
||||
std::vector<ustring> *b ) :
|
||||
impl_( new SourceDestBufferImpl( destImageFile.impl(), pathName, b ) )
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get path name in prototype that this SourceDestBuffer will transfer data to/from.
|
||||
|
||||
@details
|
||||
The prototype of a CompressedVectorNode describes the fields that are in each record. This function
|
||||
returns the path name of the node in the prototype tree that this SourceDestBuffer will write/read.
|
||||
The correctness of this path name is checked when this SourceDestBuffer is associated with a
|
||||
CompressedVectorNode (either in CompressedVectorNode::writer,
|
||||
CompressedVectorWriter::write(std::vector<SourceDestBuffer>&, unsigned),
|
||||
CompressedVectorNode::reader, CompressedVectorReader::read(std::vector<SourceDestBuffer>&)).
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return Path name in prototype that this SourceDestBuffer will transfer data to/from.
|
||||
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVector, CompressedVectorNode::prototype
|
||||
*/
|
||||
ustring SourceDestBuffer::pathName() const
|
||||
{
|
||||
return impl_->pathName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get memory representation of the elements in this SourceDestBuffer.
|
||||
|
||||
@details
|
||||
The memory representation is deduced from which overloaded SourceDestBuffer constructor was used.
|
||||
The memory representation is independent of the type and minimum/maximum bounds of the node in the
|
||||
prototype that the SourceDestBuffer will transfer to/from. However, some combinations will result in
|
||||
an error if doConversion is not requested (e.g. ::Int16 and FloatNode).
|
||||
|
||||
Some combinations risk an error occurring during a write, if a value is too large (e.g. writing an
|
||||
::Int16 memory representation to an IntegerNode with minimum=-1024 maximum=1023). Some combinations
|
||||
risk an error occurring during a read, if a value is too large (e.g. reading an IntegerNode with
|
||||
minimum=-1024 maximum=1023 int an ::Int8 memory representation). Some combinations are never
|
||||
possible (e.g. ::Int16 and StringNode).
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return Memory representation of the elements in buffer.
|
||||
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see MemoryRepresentation, NodeType
|
||||
*/
|
||||
MemoryRepresentation SourceDestBuffer::memoryRepresentation() const
|
||||
{
|
||||
return impl_->memoryRepresentation();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get total capacity of buffer.
|
||||
|
||||
@details
|
||||
The API programmer is responsible for correctly specifying the length of a buffer. This function
|
||||
returns that declared length. If the length is incorrect (in particular, too long) memory may be
|
||||
corrupted or erroneous values written.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return Total capacity of buffer.
|
||||
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
*/
|
||||
size_t SourceDestBuffer::capacity() const
|
||||
{
|
||||
return impl_->capacity();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get whether conversions will be performed to match the memory type of buffer.
|
||||
|
||||
@details
|
||||
The API user must explicitly request conversion between basic representation groups in memory and on
|
||||
the disk. The four basic representation groups are: integer, boolean, floating point, and string.
|
||||
There is no distinction between integer and boolean groups on the disk (they both use IntegerNode).
|
||||
A explicit request for conversion between single and double precision floating point representations
|
||||
is not required.
|
||||
|
||||
The most useful conversion is between integer and floating point representation groups. Conversion
|
||||
from integer to floating point representations cannot result in an overflow, and is usually
|
||||
loss-less (except for extremely large integers). Conversion from floating point to integer
|
||||
representations can result in an overflow, and can be lossy.
|
||||
|
||||
Conversion between any of the integer, boolean, and floating point representation groups is
|
||||
supported. No conversion from the string to any other representation group is possible. Missing or
|
||||
unsupported conversions are detected when the first transfer is attempted (i.e. not when the
|
||||
CompressedVectorReader or CompressedVectorWriter is created).
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return true if conversions will be performed to match the memory type of buffer.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
*/
|
||||
bool SourceDestBuffer::doConversion() const
|
||||
{
|
||||
return impl_->doConversion();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get whether scaling will be performed for ScaledIntegerNode transfers.
|
||||
|
||||
@details
|
||||
The doScaling option only applies to ScaledIntegerNodes stored in a CompressedVectorNode on the disk
|
||||
(it is ignored if a ScaledIntegerNode is not involved).
|
||||
|
||||
As a convenience, an E57 Foundation Implementation can perform scaling of data so that the API user
|
||||
can manipulate scaledValues rather than rawValues. For a reader, the scaling process is: scaledValue
|
||||
= (rawValue * scale) + offset. For a writer, the scaling process is reversed: rawValue =
|
||||
(scaledValue - offset) / scale. The result performing a scaling in a reader (or "unscaling" in a
|
||||
writer) is always a floating point number. This floating point number may have to be converted to be
|
||||
compatible with the destination representation. If the destination representation is not floating
|
||||
point, there is a risk of violating declared min/max bounds. Because of this risk, it is recommended
|
||||
that scaling only be requested for reading scaledValues from ScaledIntegerNodes into floating point
|
||||
numbers in memory.
|
||||
|
||||
It is also possible (and perhaps safest of all) to never request that scaling be performed, and
|
||||
always deal with rawValues outside the API. Note this does not mean that ScaledIntegerNodes should
|
||||
be avoided. ScaledIntegerNodes are essential for encoding numeric data with fractional parts in
|
||||
CompressedVectorNodes. Because the ASTM E57 format recommends that SI units without prefix be used
|
||||
(i.e. meters, not milli-meters or micro-furlongs), almost every measured value will have a
|
||||
fractional part.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return true if scaling will be performed for ScaledInteger transfers.
|
||||
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode
|
||||
*/
|
||||
bool SourceDestBuffer::doScaling() const
|
||||
{
|
||||
return impl_->doScaling();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get number of bytes between consecutive memory elements in buffer
|
||||
|
||||
@details
|
||||
Elements in a memory buffer do not have to be consecutive. They can also be spaced at regular
|
||||
intervals. This allows a value to be picked out of an array of C++ structures (the stride would be
|
||||
the size of the structure). In the case that the element values are stored consecutively in memory,
|
||||
the stride equals the size of the memory representation of the element.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return Number of bytes between consecutive memory elements in buffer
|
||||
*/
|
||||
size_t SourceDestBuffer::stride() const
|
||||
{
|
||||
return impl_->stride();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void SourceDestBuffer::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void SourceDestBuffer::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -36,12 +36,13 @@ namespace e57
|
||||
class SourceDestBufferImpl : public std::enable_shared_from_this<SourceDestBufferImpl>
|
||||
{
|
||||
public:
|
||||
SourceDestBufferImpl( ImageFileImplWeakPtr destImageFile, const ustring &pathName, const size_t capacity,
|
||||
bool doConversion = false, bool doScaling = false );
|
||||
SourceDestBufferImpl( ImageFileImplWeakPtr destImageFile, const ustring &pathName,
|
||||
size_t capacity, bool doConversion, bool doScaling );
|
||||
|
||||
template <typename T> void setTypeInfo( T *base, size_t stride = sizeof( T ) );
|
||||
|
||||
SourceDestBufferImpl( ImageFileImplWeakPtr destImageFile, const ustring &pathName, StringList *b );
|
||||
SourceDestBufferImpl( ImageFileImplWeakPtr destImageFile, const ustring &pathName,
|
||||
StringList *b );
|
||||
|
||||
ImageFileImplWeakPtr destImageFile() const
|
||||
{
|
||||
@@ -52,38 +53,47 @@ namespace e57
|
||||
{
|
||||
return pathName_;
|
||||
}
|
||||
|
||||
MemoryRepresentation memoryRepresentation() const
|
||||
{
|
||||
return memoryRepresentation_;
|
||||
}
|
||||
|
||||
void *base() const
|
||||
{
|
||||
return base_;
|
||||
}
|
||||
|
||||
StringList *ustrings() const
|
||||
{
|
||||
return ustrings_;
|
||||
}
|
||||
|
||||
bool doConversion() const
|
||||
{
|
||||
return doConversion_;
|
||||
}
|
||||
|
||||
bool doScaling() const
|
||||
{
|
||||
return doScaling_;
|
||||
}
|
||||
|
||||
size_t stride() const
|
||||
{
|
||||
return stride_;
|
||||
}
|
||||
|
||||
size_t capacity() const
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
unsigned nextIndex() const
|
||||
{
|
||||
return nextIndex_;
|
||||
}
|
||||
|
||||
void rewind()
|
||||
{
|
||||
nextIndex_ = 0;
|
||||
@@ -102,31 +112,44 @@ namespace e57
|
||||
|
||||
void checkCompatible( const std::shared_ptr<SourceDestBufferImpl> &newBuf ) const;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout );
|
||||
#endif
|
||||
|
||||
private:
|
||||
template <typename T> void _setNextReal( T inValue );
|
||||
|
||||
void checkState_() const; /// Common routine to check that constructor
|
||||
/// arguments were ok, throws if not
|
||||
/// Common routine to check that constructor arguments were ok, throws if not
|
||||
void checkState_() const;
|
||||
|
||||
//??? verify alignment
|
||||
ImageFileImplWeakPtr destImageFile_;
|
||||
ustring pathName_; /// Pathname from CompressedVectorNode to source/dest
|
||||
/// object, e.g. "Indices/0"
|
||||
MemoryRepresentation memoryRepresentation_; /// Type of element (e.g. E57_INT8, E57_UINT64,
|
||||
/// DOUBLE...)
|
||||
char *base_ = nullptr; /// Address of first element, for non-ustring buffers
|
||||
size_t capacity_ = 0; /// Total number of elements in array
|
||||
bool doConversion_ = false; /// Convert memory representation to/from disk representation
|
||||
bool doScaling_ = false; /// Apply scale factor for integer type
|
||||
size_t stride_ = 0; /// Distance between each element (different than size_
|
||||
/// if elements not contiguous)
|
||||
unsigned nextIndex_ = 0; /// Number of elements that have been set (dest
|
||||
/// buffer) or read (source buffer) since rewind().
|
||||
StringList *ustrings_ = nullptr; /// Optional array of ustrings (used if
|
||||
/// memoryRepresentation_==E57_USTRING) ???ownership
|
||||
|
||||
/// Pathname from CompressedVectorNode to source/dest object, e.g. "Indices/0"
|
||||
ustring pathName_;
|
||||
|
||||
/// Type of element (e.g. ::Int8, ::UIin64, ::Real64...)
|
||||
MemoryRepresentation memoryRepresentation_;
|
||||
|
||||
/// Address of first element, for non-ustring buffers
|
||||
char *base_ = nullptr;
|
||||
|
||||
/// Total number of elements in array
|
||||
size_t capacity_ = 0;
|
||||
|
||||
/// Convert memory representation to/from disk representation
|
||||
bool doConversion_ = false;
|
||||
|
||||
/// Apply scale factor for integer type
|
||||
bool doScaling_ = false;
|
||||
|
||||
/// Distance between each element (different from size_ if elements not contiguous)
|
||||
size_t stride_ = 0;
|
||||
|
||||
/// Number of elements that have been set (dest buffer) or read (source buffer) since
|
||||
/// rewind().
|
||||
unsigned nextIndex_ = 0;
|
||||
|
||||
/// Optional array of ustrings (used if memoryRepresentation_ == ::UString)
|
||||
StringList *ustrings_ = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
73
src/3rdParty/libE57Format/src/StringFunctions.cpp
vendored
Normal file
73
src/3rdParty/libE57Format/src/StringFunctions.cpp
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "StringFunctions.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <locale>
|
||||
|
||||
namespace e57
|
||||
{
|
||||
template <class FTYPE> std::string floatingPointToStr( FTYPE value, int precision )
|
||||
{
|
||||
static_assert( std::is_floating_point<FTYPE>::value, "Floating point type required." );
|
||||
|
||||
std::stringstream ss;
|
||||
ss.imbue( std::locale::classic() );
|
||||
|
||||
ss << std::scientific << std::setprecision( precision ) << value;
|
||||
|
||||
// Try to remove trailing zeroes and decimal point
|
||||
// e.g. 1.23456000000000000e+005 ==> 1.23456e+005
|
||||
// e.g. 2.00000000000000000e+005 ==> 2e+005
|
||||
|
||||
std::string s = ss.str();
|
||||
|
||||
// Split into mantissa and exponent
|
||||
// e.g. 1.23456000000000000e+005 ==> "1.23456000000000000" + "e+005"
|
||||
auto index = s.find_last_of( 'e' );
|
||||
assert( index != std::string::npos ); // should not be possible
|
||||
|
||||
std::string mantissa = s.substr( 0, index );
|
||||
const std::string exponent = s.substr( index );
|
||||
|
||||
// Double check that we understand the formatting
|
||||
if ( exponent[0] == 'e' )
|
||||
{
|
||||
// Trim trailing zeros from mantissa
|
||||
while ( mantissa.back() == '0' )
|
||||
{
|
||||
mantissa.pop_back();
|
||||
}
|
||||
|
||||
// Trim trailing decimal point if possible
|
||||
if ( mantissa.back() == '.' )
|
||||
{
|
||||
mantissa.pop_back();
|
||||
}
|
||||
|
||||
// Reassemble whole floating point number
|
||||
// Check if can drop exponent.
|
||||
if ( ( exponent == "e+00" ) || ( exponent == "e+000" ) )
|
||||
{
|
||||
s = mantissa;
|
||||
}
|
||||
else
|
||||
{
|
||||
s = mantissa + exponent;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
template std::string floatingPointToStr<float>( float value, int precision );
|
||||
template std::string floatingPointToStr<double>( double value, int precision );
|
||||
|
||||
double strToDouble( const std::string &inStr )
|
||||
{
|
||||
std::istringstream iss{ inStr };
|
||||
iss.imbue( std::locale::classic() );
|
||||
double res = 0.;
|
||||
iss >> res;
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
206
src/3rdParty/libE57Format/src/StringFunctions.h
vendored
Normal file
206
src/3rdParty/libE57Format/src/StringFunctions.h
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2022 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace e57
|
||||
{
|
||||
/// @brief Create whitespace of given length, for indenting printouts in dump() functions
|
||||
inline std::string space( size_t n )
|
||||
{
|
||||
return std::string( n, ' ' );
|
||||
}
|
||||
|
||||
/// @brief Convert number to decimal string
|
||||
template <class T> std::string toString( T x )
|
||||
{
|
||||
static_assert( std::is_integral<T>::value || std::is_enum<T>::value ||
|
||||
std::is_floating_point<T>::value,
|
||||
"Numeric type required." );
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << x;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string hexString( uint8_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "0x" << std::hex << std::setw( 2 ) << std::setfill( '0' ) << static_cast<unsigned>( x );
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string hexString( uint16_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "0x" << std::hex << std::setw( 4 ) << std::setfill( '0' ) << x;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string hexString( uint32_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "0x" << std::hex << std::setw( 8 ) << std::setfill( '0' ) << x;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string hexString( uint64_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "0x" << std::hex << std::setw( 16 ) << std::setfill( '0' ) << x;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string hexString( int8_t x )
|
||||
{
|
||||
return hexString( static_cast<uint8_t>( x ) );
|
||||
}
|
||||
|
||||
/// @brief Convert number to a hexadecimal strings
|
||||
/// @note Hex strings don't have leading zeros.
|
||||
inline std::string hexString( int16_t x )
|
||||
{
|
||||
return hexString( static_cast<uint16_t>( x ) );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string hexString( int32_t x )
|
||||
{
|
||||
return hexString( static_cast<uint32_t>( x ) );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string hexString( int64_t x )
|
||||
{
|
||||
return hexString( static_cast<uint64_t>( x ) );
|
||||
}
|
||||
|
||||
/// @brief Convert number to a binary string
|
||||
inline std::string binaryString( uint8_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for ( int i = 7; i >= 0; i-- )
|
||||
{
|
||||
ss << ( ( x & ( 1LL << i ) ) ? 1 : 0 );
|
||||
if ( i > 0 && i % 8 == 0 )
|
||||
{
|
||||
ss << " ";
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string binaryString( uint16_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for ( int i = 15; i >= 0; i-- )
|
||||
{
|
||||
ss << ( ( x & ( 1LL << i ) ) ? 1 : 0 );
|
||||
if ( i > 0 && i % 8 == 0 )
|
||||
{
|
||||
ss << " ";
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string binaryString( uint32_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for ( int i = 31; i >= 0; i-- )
|
||||
{
|
||||
ss << ( ( x & ( 1LL << i ) ) ? 1 : 0 );
|
||||
if ( i > 0 && i % 8 == 0 )
|
||||
{
|
||||
ss << " ";
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string binaryString( uint64_t x )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for ( int i = 63; i >= 0; i-- )
|
||||
{
|
||||
ss << ( ( x & ( 1LL << i ) ) ? 1 : 0 );
|
||||
if ( i > 0 && i % 8 == 0 )
|
||||
{
|
||||
ss << " ";
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string binaryString( int8_t x )
|
||||
{
|
||||
return binaryString( static_cast<uint8_t>( x ) );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string binaryString( int16_t x )
|
||||
{
|
||||
return binaryString( static_cast<uint16_t>( x ) );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string binaryString( int32_t x )
|
||||
{
|
||||
return binaryString( static_cast<uint32_t>( x ) );
|
||||
}
|
||||
|
||||
/// @overload
|
||||
inline std::string binaryString( int64_t x )
|
||||
{
|
||||
return binaryString( static_cast<uint64_t>( x ) );
|
||||
}
|
||||
|
||||
/// @brief Convert a floating point number to a string and do some clean up of the string.
|
||||
template <class FTYPE> std::string floatingPointToStr( FTYPE value, int precision );
|
||||
|
||||
extern template std::string floatingPointToStr<float>( float value, int precision );
|
||||
extern template std::string floatingPointToStr<double>( double value, int precision );
|
||||
|
||||
/// Parse a double according the the classic ("C") locale.
|
||||
/// @return The parsed double or 0.0 on error.
|
||||
double strToDouble( const std::string &inStr );
|
||||
}
|
||||
254
src/3rdParty/libE57Format/src/StringNode.cpp
vendored
Normal file
254
src/3rdParty/libE57Format/src/StringNode.cpp
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* StringNode.cpp - implementation of public functions of the StringNode class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file StringNode.cpp
|
||||
|
||||
#include "StringFunctions.h"
|
||||
#include "StringNodeImpl.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether StringNode class invariant is true
|
||||
@copydetails IntegerNode::checkInvariant()
|
||||
*/
|
||||
void StringNode::checkInvariant( bool /*doRecurse*/, bool doUpcast ) const
|
||||
{
|
||||
// If destImageFile not open, can't test invariant (almost every call would
|
||||
// throw)
|
||||
if ( !destImageFile().isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If requested, call Node::checkInvariant
|
||||
if ( doUpcast )
|
||||
{
|
||||
static_cast<Node>( *this ).checkInvariant( false, false );
|
||||
}
|
||||
// ? check legal UTF-8
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::StringNode
|
||||
|
||||
@brief An E57 element encoding a Unicode character string value.
|
||||
|
||||
@details
|
||||
A StringNode is a terminal node (i.e. having no children) that holds an Unicode character string
|
||||
encoded in UTF-8. Once the StringNode value is set at creation, it may not be modified.
|
||||
|
||||
See Node class discussion for discussion of the common functions that StructureNode supports.
|
||||
|
||||
@section StringNode_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude StringNode.cpp
|
||||
@skip void StringNode::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see Node
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Create an element storing a Unicode character string.
|
||||
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
@param [in] value The Unicode character string value of the element, in UTF-8 encoding.
|
||||
|
||||
@details
|
||||
The StringNode class corresponds to the ASTM E57 standard String element. See the class discussion
|
||||
at bottom of StringNode page for more details.
|
||||
|
||||
The @a destImageFile indicates which ImageFile the StringNode will eventually be attached to. A node
|
||||
is attached to an ImageFile by adding it underneath the predefined root of the ImageFile (gotten
|
||||
from ImageFile::root). It is not an error to fail to attach the StringNode to the @a destImageFile.
|
||||
It is an error to attempt to attach the StringNode to a different ImageFile.
|
||||
|
||||
If the StringNode is to be used in a CompressedVectorNode prototype, it is recommended to specify a
|
||||
@a value = "" (the default value).
|
||||
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StringNode::value, Node, CompressedVectorNode, CompressedVectorNode::prototype
|
||||
*/
|
||||
StringNode::StringNode( const ImageFile &destImageFile, const ustring &value ) :
|
||||
impl_( new StringNodeImpl( destImageFile.impl(), value ) )
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is this a root node.
|
||||
@copydetails Node::isRoot()
|
||||
*/
|
||||
bool StringNode::isRoot() const
|
||||
{
|
||||
return impl_->isRoot();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return parent of node, or self if a root node.
|
||||
@copydetails Node::parent()
|
||||
*/
|
||||
Node StringNode::parent() const
|
||||
{
|
||||
return Node( impl_->parent() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get absolute pathname of node.
|
||||
@copydetails Node::pathName()
|
||||
*/
|
||||
ustring StringNode::pathName() const
|
||||
{
|
||||
return impl_->pathName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get elementName string, that identifies the node in its parent.
|
||||
@copydetails Node::elementName()
|
||||
*/
|
||||
ustring StringNode::elementName() const
|
||||
{
|
||||
return impl_->elementName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the ImageFile that was declared as the destination for the node when it was created.
|
||||
@copydetails Node::destImageFile()
|
||||
*/
|
||||
ImageFile StringNode::destImageFile() const
|
||||
{
|
||||
return ImageFile( impl_->destImageFile() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Has node been attached into the tree of an ImageFile.
|
||||
@copydetails Node::isAttached()
|
||||
*/
|
||||
bool StringNode::isAttached() const
|
||||
{
|
||||
return impl_->isAttached();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get Unicode character string value stored.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@return The Unicode character string value stored.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
*/
|
||||
ustring StringNode::value() const
|
||||
{
|
||||
return impl_->value();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void StringNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void StringNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Upcast a StringNode handle to a generic Node handle.
|
||||
|
||||
@details
|
||||
An upcast is always safe, and the compiler can automatically insert it for initializations of Node
|
||||
variables and Node function arguments.
|
||||
|
||||
@return A smart Node handle referencing the underlying object.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see Explanation in Node, Node::type(), StringNode(const Node&)
|
||||
*/
|
||||
StringNode::operator Node() const
|
||||
{
|
||||
/// Upcast from shared_ptr<StringNodeImpl> to SharedNodeImplPtr and construct
|
||||
/// a Node object
|
||||
return Node( impl_ );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Downcast a generic Node handle to a StringNode handle.
|
||||
|
||||
@param [in] n The generic handle to downcast.
|
||||
|
||||
@details
|
||||
The handle @a n must be for an underlying StringNode, otherwise an exception is thrown. In designs
|
||||
that need to avoid the exception, use Node::type() to determine the actual type of the @a n before
|
||||
downcasting. This function must be explicitly called (c++ compiler cannot insert it automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
|
||||
@see Node::type(), StringNode::operator Node()
|
||||
*/
|
||||
StringNode::StringNode( const Node &n )
|
||||
{
|
||||
if ( n.type() != TypeString )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadNodeDowncast, "nodeType=" + toString( n.type() ) );
|
||||
}
|
||||
|
||||
/// Set our shared_ptr to the downcast shared_ptr
|
||||
impl_ = std::static_pointer_cast<StringNodeImpl>( n.impl() );
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
StringNode::StringNode( std::shared_ptr<StringNodeImpl> ni ) : impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
38
src/3rdParty/libE57Format/src/StringNodeImpl.cpp
vendored
38
src/3rdParty/libE57Format/src/StringNodeImpl.cpp
vendored
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "StringNodeImpl.h"
|
||||
#include "CheckedFile.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
@@ -40,15 +41,15 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// Same node type?
|
||||
if ( ni->type() != E57_STRING )
|
||||
// Same node type?
|
||||
if ( ni->type() != TypeString )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// ignore value_, doesn't have to match
|
||||
// ignore value_, doesn't have to match
|
||||
|
||||
/// Types match
|
||||
// Types match
|
||||
return ( true );
|
||||
}
|
||||
|
||||
@@ -56,7 +57,7 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// We have no sub-structure, so if path not empty return false
|
||||
// We have no sub-structure, so if path not empty return false
|
||||
return pathName.empty();
|
||||
}
|
||||
|
||||
@@ -70,10 +71,10 @@ namespace e57
|
||||
{
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// We are a leaf node, so verify that we are listed in set.
|
||||
// We are a leaf node, so verify that we are listed in set.
|
||||
if ( pathNames.find( relativePathName( origin ) ) == pathNames.end() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_NO_BUFFER_FOR_ELEMENT, "this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorNoBufferForElement, "this->pathName=" + this->pathName() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ namespace e57
|
||||
// don't checkImageFileOpen
|
||||
|
||||
ustring fieldName;
|
||||
if ( forcedFieldName )
|
||||
if ( forcedFieldName != nullptr )
|
||||
{
|
||||
fieldName = forcedFieldName;
|
||||
}
|
||||
@@ -94,7 +95,7 @@ namespace e57
|
||||
|
||||
cf << space( indent ) << "<" << fieldName << " type=\"String\"";
|
||||
|
||||
/// Write value as child text, unless it is the default value
|
||||
// Write value as child text, unless it is the default value
|
||||
if ( value_.empty() )
|
||||
{
|
||||
cf << "/>\n";
|
||||
@@ -106,38 +107,37 @@ namespace e57
|
||||
size_t currentPosition = 0;
|
||||
size_t len = value_.length();
|
||||
|
||||
/// Loop, searching for occurrences of "]]>", which will be split across
|
||||
/// two CDATA directives
|
||||
// Loop, searching for occurrences of "]]>", which will be split across two CDATA
|
||||
// directives
|
||||
while ( currentPosition < len )
|
||||
{
|
||||
size_t found = value_.find( "]]>", currentPosition );
|
||||
|
||||
if ( found == std::string::npos )
|
||||
{
|
||||
/// Didn't find any more "]]>", so can send the rest.
|
||||
// Didn't find any more "]]>", so can send the rest.
|
||||
cf << value_.substr( currentPosition );
|
||||
break;
|
||||
}
|
||||
|
||||
/// Must output in two pieces, first send up to end of "]]" (don't send
|
||||
/// the following ">").
|
||||
// Must output in two pieces, first send up to end of "]]" (don't send the following
|
||||
// ">").
|
||||
cf << value_.substr( currentPosition, found - currentPosition + 2 );
|
||||
|
||||
/// Then start a new CDATA
|
||||
// Then start a new CDATA
|
||||
cf << "]]><![CDATA[";
|
||||
|
||||
/// Keep looping to send the ">" plus the remaining part of the string
|
||||
// Keep looping to send the ">" plus the remaining part of the string
|
||||
currentPosition = found + 2;
|
||||
}
|
||||
cf << "]]></" << fieldName << ">\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void StringNodeImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
os << space( indent ) << "type: String"
|
||||
<< " (" << type() << ")" << std::endl;
|
||||
os << space( indent ) << "type: String" << " (" << type() << ")" << std::endl;
|
||||
NodeImpl::dump( indent, os );
|
||||
os << space( indent ) << "value: '" << value_ << "'" << std::endl;
|
||||
}
|
||||
|
||||
@@ -33,13 +33,14 @@ namespace e57
|
||||
class StringNodeImpl : public NodeImpl
|
||||
{
|
||||
public:
|
||||
explicit StringNodeImpl( ImageFileImplWeakPtr destImageFile, const ustring &value = "" );
|
||||
StringNodeImpl( ImageFileImplWeakPtr destImageFile, const ustring &value );
|
||||
~StringNodeImpl() override = default;
|
||||
|
||||
NodeType type() const override
|
||||
{
|
||||
return E57_STRING;
|
||||
return TypeString;
|
||||
}
|
||||
|
||||
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
|
||||
bool isDefined( const ustring &pathName ) override;
|
||||
|
||||
@@ -50,7 +51,7 @@ namespace e57
|
||||
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
|
||||
const char *forcedFieldName = nullptr ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
|
||||
413
src/3rdParty/libE57Format/src/StructureNode.cpp
vendored
Normal file
413
src/3rdParty/libE57Format/src/StructureNode.cpp
vendored
Normal file
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* StructureNode.cpp - implementation of public functions of the StructureNode class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file StructureNode.cpp
|
||||
|
||||
#include "StringFunctions.h"
|
||||
#include "StructureNodeImpl.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether StructureNode class invariant is true
|
||||
@copydetails IntegerNode::checkInvariant()
|
||||
*/
|
||||
void StructureNode::checkInvariant( bool doRecurse, bool doUpcast ) const
|
||||
{
|
||||
// If destImageFile not open, can't test invariant (almost every call would throw)
|
||||
if ( !destImageFile().isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If requested, call Node::checkInvariant
|
||||
if ( doUpcast )
|
||||
{
|
||||
static_cast<Node>( *this ).checkInvariant( false, false );
|
||||
}
|
||||
|
||||
// Check each child
|
||||
for ( int64_t i = 0; i < childCount(); i++ )
|
||||
{
|
||||
Node child = get( i );
|
||||
|
||||
// If requested, check children recursively
|
||||
if ( doRecurse )
|
||||
{
|
||||
child.checkInvariant( doRecurse, true );
|
||||
}
|
||||
|
||||
// Child's parent must be this
|
||||
if ( static_cast<Node>( *this ) != child.parent() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Child's elementName must be defined
|
||||
if ( !isDefined( child.elementName() ) )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Getting child by element name must yield same child
|
||||
Node n = get( child.elementName() );
|
||||
if ( n != child )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::StructureNode
|
||||
|
||||
@brief An E57 element containing named child nodes.
|
||||
|
||||
@details
|
||||
A StructureNode is a container of named child nodes, which may be any of the eight node types. The
|
||||
children of a structure node must have unique elementNames. Once a child node is set with a
|
||||
particular elementName, it may not be modified.
|
||||
|
||||
See Node class discussion for discussion of the common functions that StructureNode supports.
|
||||
|
||||
@section structurenode_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude StructureNode.cpp
|
||||
@skip void StructureNode::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see Node
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Create an empty StructureNode.
|
||||
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
|
||||
@details
|
||||
A StructureNode is a container for collections of named E57 nodes. The @a destImageFile indicates
|
||||
which ImageFile the StructureNode will eventually be attached to. A node is attached to an ImageFile
|
||||
by adding it underneath the predefined root of the ImageFile (gotten from ImageFile::root). It is
|
||||
not an error to fail to attach the StructureNode to the @a destImageFile. It is an error to attempt
|
||||
to attach the StructureNode to a different ImageFile.
|
||||
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node
|
||||
*/
|
||||
StructureNode::StructureNode( const ImageFile &destImageFile ) :
|
||||
impl_( new StructureNodeImpl( destImageFile.impl() ) )
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is this a root node.
|
||||
@copydetails Node::isRoot()
|
||||
*/
|
||||
bool StructureNode::isRoot() const
|
||||
{
|
||||
return impl_->isRoot();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return parent of node, or self if a root node.
|
||||
@copydetails Node::parent()
|
||||
*/
|
||||
Node StructureNode::parent() const
|
||||
{
|
||||
return Node( impl_->parent() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get absolute pathname of node.
|
||||
@copydetails Node::pathName()
|
||||
*/
|
||||
ustring StructureNode::pathName() const
|
||||
{
|
||||
return impl_->pathName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get elementName string, that identifies the node in its parent.
|
||||
@copydetails Node::elementName()
|
||||
*/
|
||||
ustring StructureNode::elementName() const
|
||||
{
|
||||
return impl_->elementName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the ImageFile that was declared as the destination for the node when it was created.
|
||||
@copydetails Node::destImageFile()
|
||||
*/
|
||||
ImageFile StructureNode::destImageFile() const
|
||||
{
|
||||
return ImageFile( impl_->destImageFile() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Has node been attached into the tree of an ImageFile.
|
||||
@copydetails Node::isAttached()
|
||||
*/
|
||||
bool StructureNode::isAttached() const
|
||||
{
|
||||
return impl_->isAttached();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return number of child nodes contained by this StructureNode.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return Number of child nodes contained by this StructureNode.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StructureNode::get(int64_t) const,
|
||||
StructureNode::set, VectorNode::childCount
|
||||
*/
|
||||
int64_t StructureNode::childCount() const
|
||||
{
|
||||
return impl_->childCount();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is the given pathName defined relative to this node.
|
||||
|
||||
@param [in] pathName The absolute pathname, or pathname relative to this object, to check.
|
||||
|
||||
@details
|
||||
The @a pathName may be relative to this node, or absolute (starting with a "/"). The origin of the
|
||||
absolute path name is the root of the tree that contains this StructureNode. If this StructureNode
|
||||
is not attached to an ImageFile, the @a pathName origin root will not the root node of an ImageFile.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return true if pathName is currently defined.
|
||||
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::root, VectorNode::isDefined
|
||||
*/
|
||||
bool StructureNode::isDefined( const ustring &pathName ) const
|
||||
{
|
||||
return impl_->isDefined( pathName );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get a child element by positional index.
|
||||
|
||||
@param [in] index The index of child element to get, starting at 0.
|
||||
|
||||
@details
|
||||
The order of children is not specified, and may be different than order the children were added to
|
||||
the StructureNode. The order of children may change if more children are added to the StructureNode.
|
||||
|
||||
@pre 0 <= @a index < childCount()
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return A smart Node handle referencing the child node.
|
||||
|
||||
@throw ::ErrorChildIndexOutOfBounds
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StructureNode::childCount,
|
||||
StructureNode::get(const ustring&) const, VectorNode::get
|
||||
*/
|
||||
Node StructureNode::get( int64_t index ) const
|
||||
{
|
||||
return Node( impl_->get( index ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get a child by path name.
|
||||
|
||||
@param [in] pathName The absolute pathname, or pathname relative to this object, of the object to
|
||||
get. The @a pathName may be relative to this node, or absolute (starting with a "/"). The origin of
|
||||
the absolute path name is the root of the tree that contains this StructureNode. If this
|
||||
StructureNode is not attached to an ImageFile, the @a pathName origin root will not the root node of
|
||||
an ImageFile.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@pre The @a pathName must be defined (i.e. isDefined(pathName)).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return A smart Node handle referencing the child node.
|
||||
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StructureNode::get(int64_t) const
|
||||
*/
|
||||
Node StructureNode::get( const ustring &pathName ) const
|
||||
{
|
||||
return Node( impl_->get( pathName ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Add a new child at a given path
|
||||
|
||||
@param [in] pathName The absolute pathname, or pathname relative to this object, that the child
|
||||
object @a n will be given.
|
||||
@param [in] n The node to be added to the tree with given @a pathName.
|
||||
|
||||
@details
|
||||
The @a pathName may be relative to this node, or absolute (starting with a "/"). The origin of the
|
||||
absolute path name is the root of the tree that contains this StructureNode. If this StructureNode
|
||||
is not attached to an ImageFile, the @a pathName origin root will not the root node of an ImageFile.
|
||||
|
||||
The path name formed from all element names in @a pathName except the last must exist. If the @a
|
||||
pathName identifies the child of a VectorNode, then the last element name in @a pathName must be
|
||||
numeric, and be equal to the childCount of that VectorNode (the request is equivalent to
|
||||
VectorNode::append). The StructureNode must not be a descendent of a homogeneous VectorNode with
|
||||
more than one child.
|
||||
|
||||
The element naming grammar specified by the ASTM E57 format standard are not enforced in this
|
||||
function. This would be very difficult to do dynamically, as some of the naming rules involve
|
||||
combinations of names.
|
||||
|
||||
@pre The new child node @a n must be a root node (i.e. n.isRoot()).
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@pre The associated destImageFile must have been opened in write mode (i.e.
|
||||
destImageFile().isWritable()).
|
||||
@pre The @a pathName must not already be defined (i.e. !isDefined(pathName)).
|
||||
@pre The associated destImageFile of this StructureNode and of @a n must be same (i.e.
|
||||
destImageFile() == n.destImageFile()).
|
||||
@post The @a pathName will be defined (i.e. isDefined(pathName)).
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorSetTwice
|
||||
@throw ::ErrorAlreadyHasParent
|
||||
@throw ::ErrorDifferentDestImageFile
|
||||
@throw ::ErrorHomogeneousViolation
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see VectorNode::append
|
||||
*/
|
||||
void StructureNode::set( const ustring &pathName, const Node &n )
|
||||
{
|
||||
impl_->set( pathName, n.impl(), false );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void StructureNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void StructureNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Upcast a StructureNode handle to a generic Node handle.
|
||||
|
||||
@details
|
||||
An upcast is always safe, and the compiler can automatically insert it for initializations of Node
|
||||
variables and Node function arguments.
|
||||
|
||||
@return A smart Node handle referencing the underlying object.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see explanation in Node, Node::type(), StructureNode(const Node&)
|
||||
*/
|
||||
StructureNode::operator Node() const
|
||||
{
|
||||
// Implicitly upcast from shared_ptr<StructureNodeImpl> to SharedNodeImplPtr and construct a Node
|
||||
// object
|
||||
return Node( impl_ );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Downcast a generic Node handle to a StructureNode handle.
|
||||
|
||||
@param [in] n The generic handle to downcast.
|
||||
|
||||
@details
|
||||
The handle @a n must be for an underlying StructureNode, otherwise an exception is thrown. In
|
||||
designs that need to avoid the exception, use Node::type() to determine the actual type of the @a n
|
||||
before downcasting. This function must be explicitly called (c++ compiler cannot insert it
|
||||
automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
|
||||
@see Node::type(), StructureNode::operator Node()
|
||||
*/
|
||||
StructureNode::StructureNode( const Node &n )
|
||||
{
|
||||
if ( n.type() != TypeStructure )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadNodeDowncast, "nodeType=" + toString( n.type() ) );
|
||||
}
|
||||
|
||||
// Set our shared_ptr to the downcast shared_ptr
|
||||
impl_ = std::static_pointer_cast<StructureNodeImpl>( n.impl() );
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
StructureNode::StructureNode( std::weak_ptr<ImageFileImpl> fileParent ) :
|
||||
impl_( new StructureNodeImpl( fileParent ) )
|
||||
{
|
||||
}
|
||||
|
||||
StructureNode::StructureNode( std::shared_ptr<StructureNodeImpl> ni ) : impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
231
src/3rdParty/libE57Format/src/StructureNodeImpl.cpp
vendored
231
src/3rdParty/libE57Format/src/StructureNodeImpl.cpp
vendored
@@ -29,46 +29,48 @@
|
||||
|
||||
#include "CheckedFile.h"
|
||||
#include "ImageFileImpl.h"
|
||||
#include "StringFunctions.h"
|
||||
#include "StructureNodeImpl.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
StructureNodeImpl::StructureNodeImpl( ImageFileImplWeakPtr destImageFile ) : NodeImpl( destImageFile )
|
||||
StructureNodeImpl::StructureNodeImpl( ImageFileImplWeakPtr destImageFile ) :
|
||||
NodeImpl( destImageFile )
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
}
|
||||
|
||||
NodeType StructureNodeImpl::type() const
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
return E57_STRUCTURE;
|
||||
// don't checkImageFileOpen
|
||||
return TypeStructure;
|
||||
}
|
||||
|
||||
//??? use visitor?
|
||||
bool StructureNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// Same node type?
|
||||
if ( ni->type() != E57_STRUCTURE )
|
||||
// Same node type?
|
||||
if ( ni->type() != TypeStructure )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// Downcast to shared_ptr<StructureNodeImpl>
|
||||
// Downcast to shared_ptr<StructureNodeImpl>
|
||||
std::shared_ptr<StructureNodeImpl> si( std::static_pointer_cast<StructureNodeImpl>( ni ) );
|
||||
|
||||
/// Same number of children?
|
||||
// Same number of children?
|
||||
if ( childCount() != si->childCount() )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// Check each child is equivalent
|
||||
// Check each child is equivalent
|
||||
for ( unsigned i = 0; i < childCount(); i++ )
|
||||
{ //??? vector iterator?
|
||||
ustring myChildsFieldName = children_.at( i )->elementName();
|
||||
/// Check if matching field name is in same position (to speed things up)
|
||||
// Check if matching field name is in same position (to speed things up)
|
||||
if ( myChildsFieldName == si->children_.at( i )->elementName() )
|
||||
{
|
||||
if ( !children_.at( i )->isTypeEquivalent( si->children_.at( i ) ) )
|
||||
@@ -78,8 +80,7 @@ bool StructureNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Children in different order, so lookup by name and check if equal
|
||||
/// to our child
|
||||
// Children in different order, so lookup by name and check if equal to our child
|
||||
if ( !si->isDefined( myChildsFieldName ) )
|
||||
{
|
||||
return ( false );
|
||||
@@ -91,7 +92,7 @@ bool StructureNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
|
||||
}
|
||||
}
|
||||
|
||||
/// Types match
|
||||
// Types match
|
||||
return ( true );
|
||||
}
|
||||
|
||||
@@ -104,10 +105,10 @@ bool StructureNodeImpl::isDefined( const ustring &pathName )
|
||||
|
||||
void StructureNodeImpl::setAttachedRecursive()
|
||||
{
|
||||
/// Mark this node as attached to an ImageFile
|
||||
// Mark this node as attached to an ImageFile
|
||||
isAttached_ = true;
|
||||
|
||||
/// Not a leaf node, so mark all our children
|
||||
// Not a leaf node, so mark all our children
|
||||
for ( auto &child : children_ )
|
||||
{
|
||||
child->setAttachedRecursive();
|
||||
@@ -120,14 +121,15 @@ int64_t StructureNodeImpl::childCount() const
|
||||
|
||||
return children_.size();
|
||||
}
|
||||
|
||||
NodeImplSharedPtr StructureNodeImpl::get( int64_t index )
|
||||
{
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
if ( index < 0 || index >= static_cast<int64_t>( children_.size() ) )
|
||||
{ // %%% Possible truncation on platforms where size_t = uint64
|
||||
throw E57_EXCEPTION2( E57_ERROR_CHILD_INDEX_OUT_OF_BOUNDS, "this->pathName=" + this->pathName() +
|
||||
" index=" + toString( index ) +
|
||||
" size=" + toString( children_.size() ) );
|
||||
throw E57_EXCEPTION2( ErrorChildIndexOutOfBounds,
|
||||
"this->pathName=" + this->pathName() + " index=" + toString( index ) +
|
||||
" size=" + toString( children_.size() ) );
|
||||
}
|
||||
return ( children_.at( static_cast<unsigned>( index ) ) );
|
||||
}
|
||||
@@ -139,14 +141,15 @@ NodeImplSharedPtr StructureNodeImpl::get( const ustring &pathName )
|
||||
|
||||
if ( !ni )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_PATH_UNDEFINED, "this->pathName=" + this->pathName() + " pathName=" + pathName );
|
||||
throw E57_EXCEPTION2( ErrorPathUndefined,
|
||||
"this->pathName=" + this->pathName() + " pathName=" + pathName );
|
||||
}
|
||||
return ( ni );
|
||||
}
|
||||
|
||||
NodeImplSharedPtr StructureNodeImpl::lookup( const ustring &pathName )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
//??? use lookup(fields, level) instead, for speed.
|
||||
bool isRelative;
|
||||
std::vector<ustring> fields;
|
||||
@@ -159,51 +162,46 @@ NodeImplSharedPtr StructureNodeImpl::lookup( const ustring &pathName )
|
||||
{
|
||||
if ( isRelative )
|
||||
{
|
||||
return NodeImplSharedPtr(); /// empty pointer
|
||||
}
|
||||
else
|
||||
{
|
||||
NodeImplSharedPtr root( getRoot() );
|
||||
return ( root );
|
||||
return {}; // empty pointer
|
||||
}
|
||||
|
||||
NodeImplSharedPtr root( getRoot() );
|
||||
return ( root );
|
||||
}
|
||||
else
|
||||
|
||||
// Find child with elementName that matches first field in path
|
||||
unsigned i;
|
||||
for ( i = 0; i < children_.size(); i++ )
|
||||
{
|
||||
/// Find child with elementName that matches first field in path
|
||||
unsigned i;
|
||||
for ( i = 0; i < children_.size(); i++ )
|
||||
if ( fields.at( 0 ) == children_.at( i )->elementName() )
|
||||
{
|
||||
if ( fields.at( 0 ) == children_.at( i )->elementName() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( i == children_.size() )
|
||||
{
|
||||
return NodeImplSharedPtr(); /// empty pointer
|
||||
}
|
||||
|
||||
if ( fields.size() == 1 )
|
||||
{
|
||||
return ( children_.at( i ) );
|
||||
}
|
||||
|
||||
//??? use level here rather than unparse
|
||||
/// Remove first field in path
|
||||
fields.erase( fields.begin() );
|
||||
|
||||
/// Call lookup on child object with remaining fields in path name
|
||||
return children_.at( i )->lookup( imf->pathNameUnparse( true, fields ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /// Absolute pathname and we aren't at the root
|
||||
/// Find root of the tree
|
||||
NodeImplSharedPtr root( getRoot() );
|
||||
if ( i == children_.size() )
|
||||
{
|
||||
return {}; // empty pointer
|
||||
}
|
||||
|
||||
/// Call lookup on root
|
||||
return ( root->lookup( pathName ) );
|
||||
if ( fields.size() == 1 )
|
||||
{
|
||||
return ( children_.at( i ) );
|
||||
}
|
||||
|
||||
//??? use level here rather than unparse
|
||||
// Remove first field in path
|
||||
fields.erase( fields.begin() );
|
||||
|
||||
// Call lookup on child object with remaining fields in path name
|
||||
return children_.at( i )->lookup( imf->pathNameUnparse( true, fields ) );
|
||||
}
|
||||
|
||||
// Absolute pathname and we aren't at the root
|
||||
// Find root of the tree
|
||||
NodeImplSharedPtr root( getRoot() );
|
||||
|
||||
// Call lookup on root
|
||||
return ( root->lookup( pathName ) );
|
||||
}
|
||||
|
||||
void StructureNodeImpl::set( int64_t index64, NodeImplSharedPtr ni )
|
||||
@@ -212,38 +210,39 @@ void StructureNodeImpl::set( int64_t index64, NodeImplSharedPtr ni )
|
||||
|
||||
auto index = static_cast<unsigned>( index64 );
|
||||
|
||||
/// Allow index == current number of elements, interpret as append
|
||||
// Allow index == current number of elements, interpret as append
|
||||
if ( index64 < 0 || index64 > UINT_MAX || index > children_.size() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_CHILD_INDEX_OUT_OF_BOUNDS, "this->pathName=" + this->pathName() +
|
||||
" index=" + toString( index64 ) +
|
||||
" size=" + toString( children_.size() ) );
|
||||
throw E57_EXCEPTION2( ErrorChildIndexOutOfBounds,
|
||||
"this->pathName=" + this->pathName() + " index=" + toString( index64 ) +
|
||||
" size=" + toString( children_.size() ) );
|
||||
}
|
||||
|
||||
/// Enforce "set once" policy, only allow append
|
||||
// Enforce "set once" policy, only allow append
|
||||
if ( index != children_.size() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_SET_TWICE,
|
||||
"this->pathName=" + this->pathName() + " index=" + toString( index64 ) );
|
||||
throw E57_EXCEPTION2( ErrorSetTwice, "this->pathName=" + this->pathName() +
|
||||
" index=" + toString( index64 ) );
|
||||
}
|
||||
|
||||
/// Verify that child is destined for same ImageFile as this is
|
||||
// Verify that child is destined for same ImageFile as this is
|
||||
ImageFileImplSharedPtr thisDest( destImageFile() );
|
||||
ImageFileImplSharedPtr niDest( ni->destImageFile() );
|
||||
if ( thisDest != niDest )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_DIFFERENT_DEST_IMAGEFILE,
|
||||
"this->destImageFile" + thisDest->fileName() + " ni->destImageFile" + niDest->fileName() );
|
||||
throw E57_EXCEPTION2( ErrorDifferentDestImageFile,
|
||||
"this->destImageFile" + thisDest->fileName() + " ni->destImageFile" +
|
||||
niDest->fileName() );
|
||||
}
|
||||
|
||||
/// Field name is string version of index value, e.g. "14"
|
||||
// Field name is string version of index value, e.g. "14"
|
||||
std::stringstream elementName;
|
||||
elementName << index;
|
||||
|
||||
/// If this struct is type constrained, can't add new child
|
||||
// If this struct is type constrained, can't add new child
|
||||
if ( isTypeConstrained() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_HOMOGENEOUS_VIOLATION, "this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorHomogeneousViolation, "this->pathName=" + this->pathName() );
|
||||
}
|
||||
|
||||
ni->setParent( shared_from_this(), elementName.str() );
|
||||
@@ -258,34 +257,33 @@ void StructureNodeImpl::set( const ustring &pathName, NodeImplSharedPtr ni, bool
|
||||
// types for VECTOR,
|
||||
// COMPRESSED_VECTOR
|
||||
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
std::cout << "StructureNodeImpl::set(pathName=" << pathName << ", ni, autoPathCreate=" << autoPathCreate
|
||||
<< std::endl;
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "StructureNodeImpl::set(pathName=" << pathName
|
||||
<< ", ni, autoPathCreate=" << autoPathCreate << std::endl;
|
||||
#endif
|
||||
|
||||
bool isRelative;
|
||||
std::vector<ustring> fields;
|
||||
|
||||
/// Path may be absolute or relative with several levels. Break string into
|
||||
/// individual levels.
|
||||
// Path may be absolute or relative with several levels. Break string into individual levels.
|
||||
ImageFileImplSharedPtr imf( destImageFile_ );
|
||||
imf->pathNameParse( pathName, isRelative, fields ); // throws if bad pathName
|
||||
if ( isRelative )
|
||||
{
|
||||
/// Relative path, starting from current object, e.g. "foo/17/bar"
|
||||
// Relative path, starting from current object, e.g. "foo/17/bar"
|
||||
set( fields, 0, ni, autoPathCreate );
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Absolute path (starting from root), e.g. "/foo/17/bar"
|
||||
// Absolute path (starting from root), e.g. "/foo/17/bar"
|
||||
getRoot()->set( fields, 0, ni, autoPathCreate );
|
||||
}
|
||||
}
|
||||
|
||||
void StructureNodeImpl::set( const std::vector<ustring> &fields, unsigned level, NodeImplSharedPtr ni,
|
||||
bool autoPathCreate )
|
||||
void StructureNodeImpl::set( const std::vector<ustring> &fields, unsigned level,
|
||||
NodeImplSharedPtr ni, bool autoPathCreate )
|
||||
{
|
||||
#ifdef E57_MAX_VERBOSE
|
||||
#ifdef E57_VERBOSE
|
||||
std::cout << "StructureNodeImpl::set: level=" << level << std::endl;
|
||||
for ( unsigned i = 0; i < fields.size(); i++ )
|
||||
{
|
||||
@@ -298,58 +296,56 @@ void StructureNodeImpl::set( const std::vector<ustring> &fields, unsigned level,
|
||||
// index, else throw
|
||||
// bad_path
|
||||
|
||||
/// Check if trying to set the root node "/", which is illegal
|
||||
// Check if trying to set the root node "/", which is illegal
|
||||
if ( level == 0 && fields.empty() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_SET_TWICE, "this->pathName=" + this->pathName() + " element=/" );
|
||||
throw E57_EXCEPTION2( ErrorSetTwice, "this->pathName=" + this->pathName() + " element=/" );
|
||||
}
|
||||
|
||||
/// Serial search for matching field name, if find match, have error since
|
||||
/// can't set twice
|
||||
// Serial search for matching field name, if find match, have error since can't set twice
|
||||
for ( auto &child : children_ )
|
||||
{
|
||||
if ( fields.at( level ) == child->elementName() )
|
||||
{
|
||||
if ( level == fields.size() - 1 )
|
||||
{
|
||||
/// Enforce "set once" policy, don't allow reset
|
||||
throw E57_EXCEPTION2( E57_ERROR_SET_TWICE,
|
||||
"this->pathName=" + this->pathName() + " element=" + fields[level] );
|
||||
// Enforce "set once" policy, don't allow reset
|
||||
throw E57_EXCEPTION2( ErrorSetTwice, "this->pathName=" + this->pathName() +
|
||||
" element=" + fields[level] );
|
||||
}
|
||||
|
||||
/// Recurse on child
|
||||
// Recurse on child
|
||||
child->set( fields, level + 1, ni );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
/// Didn't find matching field name, so have a new child.
|
||||
// Didn't find matching field name, so have a new child.
|
||||
|
||||
/// If this struct is type constrained, can't add new child
|
||||
// If this struct is type constrained, can't add new child
|
||||
if ( isTypeConstrained() )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_HOMOGENEOUS_VIOLATION, "this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorHomogeneousViolation, "this->pathName=" + this->pathName() );
|
||||
}
|
||||
|
||||
/// Check if we are at bottom level
|
||||
// Check if we are at bottom level
|
||||
if ( level == fields.size() - 1 )
|
||||
{
|
||||
/// At bottom, so append node at end of children
|
||||
// At bottom, so append node at end of children
|
||||
ni->setParent( shared_from_this(), fields.at( level ) );
|
||||
children_.push_back( ni );
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Not at bottom level, if not autoPathCreate have an error
|
||||
// Not at bottom level, if not autoPathCreate have an error
|
||||
if ( !autoPathCreate )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_PATH_UNDEFINED,
|
||||
"this->pathName=" + this->pathName() + " field=" + fields.at( level ) );
|
||||
throw E57_EXCEPTION2( ErrorPathUndefined, "this->pathName=" + this->pathName() +
|
||||
" field=" + fields.at( level ) );
|
||||
}
|
||||
//??? what if extra fields are numbers?
|
||||
|
||||
/// Do autoPathCreate: Create nested Struct objects for extra field names
|
||||
/// in path
|
||||
// Do autoPathCreate: Create nested Struct objects for extra field names in path
|
||||
NodeImplSharedPtr parent( shared_from_this() );
|
||||
for ( ; level != fields.size() - 1; level++ )
|
||||
{
|
||||
@@ -363,18 +359,18 @@ void StructureNodeImpl::set( const std::vector<ustring> &fields, unsigned level,
|
||||
|
||||
void StructureNodeImpl::append( NodeImplSharedPtr ni )
|
||||
{
|
||||
/// don't checkImageFileOpen, set() will do it
|
||||
// don't checkImageFileOpen, set() will do it
|
||||
|
||||
/// Create new node at end of list with integer field name
|
||||
// Create new node at end of list with integer field name
|
||||
set( childCount(), ni );
|
||||
}
|
||||
|
||||
//??? use visitor?
|
||||
void StructureNodeImpl::checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// Not a leaf node, so check all our children
|
||||
// Not a leaf node, so check all our children
|
||||
for ( auto &child : children_ )
|
||||
{
|
||||
child->checkLeavesInSet( pathNames, origin );
|
||||
@@ -382,12 +378,13 @@ void StructureNodeImpl::checkLeavesInSet( const StringSet &pathNames, NodeImplSh
|
||||
}
|
||||
|
||||
//??? use visitor?
|
||||
void StructureNodeImpl::writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent, const char *forcedFieldName )
|
||||
void StructureNodeImpl::writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
|
||||
const char *forcedFieldName )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
|
||||
ustring fieldName;
|
||||
if ( forcedFieldName )
|
||||
if ( forcedFieldName != nullptr )
|
||||
{
|
||||
fieldName = forcedFieldName;
|
||||
}
|
||||
@@ -400,9 +397,9 @@ void StructureNodeImpl::writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, i
|
||||
|
||||
const int numSpaces = indent + static_cast<int>( fieldName.length() ) + 2;
|
||||
|
||||
/// If this struct is the root for the E57 file, add name space declarations
|
||||
/// Note the prototype of a CompressedVector is a separate tree, so don't
|
||||
/// want to write out namespaces if not the ImageFile root
|
||||
// If this struct is the root for the E57 file, add name space declarations. Note the prototype
|
||||
// of a CompressedVector is a separate tree, so don't want to write out namespaces if not the
|
||||
// ImageFile root
|
||||
if ( isRoot() && shared_from_this() == imf->root() )
|
||||
{
|
||||
bool gotDefaultNamespace = false;
|
||||
@@ -426,40 +423,38 @@ void StructureNodeImpl::writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, i
|
||||
<< imf->extensionsUri( index ) << "\"";
|
||||
}
|
||||
|
||||
/// If user didn't explicitly declare a default namespace, use the current
|
||||
/// E57 standard one.
|
||||
// If user didn't explicitly declare a default namespace, use the current E57 standard one.
|
||||
if ( !gotDefaultNamespace )
|
||||
{
|
||||
cf << "\n" << space( numSpaces ) << "xmlns=\"" << E57_V1_0_URI << "\"";
|
||||
cf << "\n" << space( numSpaces ) << "xmlns=\"" << VERSION_1_0_URI << "\"";
|
||||
}
|
||||
}
|
||||
if ( !children_.empty() )
|
||||
{
|
||||
cf << ">\n";
|
||||
|
||||
/// Write all children nested inside Structure element
|
||||
// Write all children nested inside Structure element
|
||||
for ( auto &child : children_ )
|
||||
{
|
||||
child->writeXml( imf, cf, indent + 2 );
|
||||
}
|
||||
|
||||
/// Write closing tag
|
||||
// Write closing tag
|
||||
cf << space( indent ) << "</" << fieldName << ">\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
/// XML element has no child elements
|
||||
// XML element has no child elements
|
||||
cf << "/>\n";
|
||||
}
|
||||
}
|
||||
|
||||
//??? use visitor?
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void StructureNodeImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
os << space( indent ) << "type: Structure"
|
||||
<< " (" << type() << ")" << std::endl;
|
||||
// don't checkImageFileOpen
|
||||
os << space( indent ) << "type: Structure" << " (" << type() << ")" << std::endl;
|
||||
NodeImpl::dump( indent, os );
|
||||
for ( unsigned i = 0; i < children_.size(); i++ )
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace e57
|
||||
class StructureNodeImpl : public NodeImpl
|
||||
{
|
||||
public:
|
||||
StructureNodeImpl( ImageFileImplWeakPtr destImageFile );
|
||||
explicit StructureNodeImpl( ImageFileImplWeakPtr destImageFile );
|
||||
~StructureNodeImpl() override = default;
|
||||
|
||||
NodeType type() const override;
|
||||
@@ -49,8 +49,10 @@ namespace e57
|
||||
NodeImplSharedPtr get( const ustring &pathName ) override;
|
||||
|
||||
virtual void set( int64_t index, NodeImplSharedPtr ni );
|
||||
void set( const ustring &pathName, NodeImplSharedPtr ni, bool autoPathCreate = false ) override;
|
||||
void set( const StringList &fields, unsigned level, NodeImplSharedPtr ni, bool autoPathCreate = false ) override;
|
||||
void set( const ustring &pathName, NodeImplSharedPtr ni,
|
||||
bool autoPathCreate = false ) override;
|
||||
void set( const StringList &fields, unsigned level, NodeImplSharedPtr ni,
|
||||
bool autoPathCreate = false ) override;
|
||||
virtual void append( NodeImplSharedPtr ni );
|
||||
|
||||
void checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin ) override;
|
||||
@@ -58,12 +60,13 @@ namespace e57
|
||||
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
|
||||
const char *forcedFieldName = nullptr ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
friend class CompressedVectorReaderImpl;
|
||||
|
||||
NodeImplSharedPtr lookup( const ustring &pathName ) override;
|
||||
|
||||
std::vector<NodeImplSharedPtr> children_;
|
||||
|
||||
435
src/3rdParty/libE57Format/src/VectorNode.cpp
vendored
Normal file
435
src/3rdParty/libE57Format/src/VectorNode.cpp
vendored
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* VectorNode.cpp - implementation of public functions of the VectorNode class.
|
||||
*
|
||||
* Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
|
||||
* Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/// @file VectorNode.cpp
|
||||
|
||||
#include "StringFunctions.h"
|
||||
#include "VectorNodeImpl.h"
|
||||
|
||||
using namespace e57;
|
||||
|
||||
// Put this function first so we can reference the code in doxygen using @skip
|
||||
/*!
|
||||
@brief Check whether VectorNode class invariant is true
|
||||
@copydetails IntegerNode::checkInvariant()
|
||||
*/
|
||||
void VectorNode::checkInvariant( bool doRecurse, bool doUpcast ) const
|
||||
{
|
||||
// If destImageFile not open, can't test invariant (almost every call would throw)
|
||||
if ( !destImageFile().isOpen() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If requested, call Node::checkInvariant
|
||||
if ( doUpcast )
|
||||
{
|
||||
static_cast<Node>( *this ).checkInvariant( false, false );
|
||||
}
|
||||
|
||||
// Check each child
|
||||
for ( int64_t i = 0; i < childCount(); i++ )
|
||||
{
|
||||
Node child = get( i );
|
||||
|
||||
// If requested, check children recursively
|
||||
if ( doRecurse )
|
||||
{
|
||||
child.checkInvariant( doRecurse, true );
|
||||
}
|
||||
|
||||
// Child's parent must be this
|
||||
if ( static_cast<Node>( *this ) != child.parent() )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Child's elementName must be defined
|
||||
if ( !isDefined( child.elementName() ) )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
|
||||
// Getting child by element name must yield same child
|
||||
Node n = get( child.elementName() );
|
||||
if ( n != child )
|
||||
{
|
||||
throw E57_EXCEPTION1( ErrorInvarianceViolation );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class e57::VectorNode
|
||||
|
||||
@brief An E57 element containing ordered vector of child nodes.
|
||||
|
||||
@details
|
||||
A VectorNode is a container of ordered child nodes. The child nodes are automatically assigned an
|
||||
elementName, which is a string version of the positional index of the child starting at "0". Child
|
||||
nodes may only be appended onto the end of a VectorNode.
|
||||
|
||||
A VectorNode that is created with a restriction that its children must have the same type is called
|
||||
a "homogeneous VectorNode". A VectorNode without such a restriction is called a "heterogeneous
|
||||
VectorNode".
|
||||
|
||||
See Node class discussion for discussion of the common functions that StructureNode supports.
|
||||
|
||||
@section vectornode_invariant Class Invariant
|
||||
A class invariant is a list of statements about an object that are always true before and after any
|
||||
operation on the object. An invariant is useful for testing correct operation of an implementation.
|
||||
Statements in an invariant can involve only externally visible state, or can refer to internal
|
||||
implementation-specific state that is not visible to the API user. The following C++ code checks
|
||||
externally visible state for consistency and throws an exception if the invariant is violated:
|
||||
|
||||
@dontinclude VectorNode.cpp
|
||||
@skip void VectorNode::checkInvariant
|
||||
@until ^}
|
||||
|
||||
@see Node
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Create a new empty Vector node.
|
||||
|
||||
@param [in] destImageFile The ImageFile where the new node will eventually be stored.
|
||||
@param [in] allowHeteroChildren Will child elements of differing types be allowed in this
|
||||
VectorNode.
|
||||
|
||||
@details
|
||||
A VectorNode is a ordered container of E57 nodes.
|
||||
|
||||
The @a destImageFile indicates which ImageFile the VectorNode will eventually be attached to. A node
|
||||
is attached to an ImageFile by adding it underneath the predefined root of the ImageFile (gotten
|
||||
from ImageFile::root). It is not an error to fail to attach the VectorNode to the @a destImageFile.
|
||||
It is an error to attempt to attach the VectorNode to a different ImageFile.
|
||||
|
||||
If @a allowHeteroChildren is false, then the children that are appended to the VectorNode must be
|
||||
identical in every visible characteristic except the stored values. These visible characteristics
|
||||
include number of children (for StructureNode and VectorNode descendents), number of
|
||||
records/prototypes/codecs (for CompressedVectorNode), minimum/maximum attributes (for IntegerNode,
|
||||
ScaledIntegerNode, FloatNode), byteCount (for BlobNode), scale/offset (for ScaledIntegerNode), and
|
||||
all elementNames. The enforcement of this homogeneity rule begins when the second child is appended
|
||||
to the VectorNode, thus it is not an error to modify a child of a homogeneous VectorNode containing
|
||||
only one child.
|
||||
|
||||
If @a allowHeteroChildren is true, then the types of the children of the VectorNode are completely
|
||||
unconstrained.
|
||||
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node, VectorNode::allowHeteroChildren, ::ErrorHomogeneousViolation
|
||||
*/
|
||||
VectorNode::VectorNode( const ImageFile &destImageFile, bool allowHeteroChildren ) :
|
||||
impl_( new VectorNodeImpl( destImageFile.impl(), allowHeteroChildren ) )
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is this a root node.
|
||||
@copydetails Node::isRoot()
|
||||
*/
|
||||
bool VectorNode::isRoot() const
|
||||
{
|
||||
return impl_->isRoot();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Return parent of node, or self if a root node.
|
||||
@copydetails Node::parent()
|
||||
*/
|
||||
Node VectorNode::parent() const
|
||||
{
|
||||
return Node( impl_->parent() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get absolute pathname of node.
|
||||
@copydetails Node::pathName()
|
||||
*/
|
||||
ustring VectorNode::pathName() const
|
||||
{
|
||||
return impl_->pathName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get elementName string, that identifies the node in its parent.
|
||||
@copydetails Node::elementName()
|
||||
*/
|
||||
ustring VectorNode::elementName() const
|
||||
{
|
||||
return impl_->elementName();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the ImageFile that was declared as the destination for the node when it was created.
|
||||
@copydetails Node::destImageFile()
|
||||
*/
|
||||
ImageFile VectorNode::destImageFile() const
|
||||
{
|
||||
return ImageFile( impl_->destImageFile() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Has node been attached into the tree of an ImageFile.
|
||||
@copydetails Node::isAttached()
|
||||
*/
|
||||
bool VectorNode::isAttached() const
|
||||
{
|
||||
return impl_->isAttached();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get whether child elements are allowed to be different types
|
||||
|
||||
@details
|
||||
See the class discussion at bottom of VectorNode page for details of homogeneous/heterogeneous
|
||||
VectorNode. The returned attribute is determined when the VectorNode is created, and cannot be
|
||||
changed.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return True if child elements can be different types.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ::ErrorHomogeneousViolation
|
||||
*/
|
||||
bool VectorNode::allowHeteroChildren() const
|
||||
{
|
||||
return impl_->allowHeteroChildren();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get number of child elements in this VectorNode.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return Number of child elements in this VectorNode.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see VectorNode::get(int64_t), VectorNode::append, StructureNode::childCount
|
||||
*/
|
||||
int64_t VectorNode::childCount() const
|
||||
{
|
||||
return impl_->childCount();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Is the given pathName defined relative to this node.
|
||||
|
||||
@param [in] pathName The absolute pathname, or pathname relative to this object, to check.
|
||||
|
||||
@details
|
||||
The @a pathName may be relative to this node, or absolute (starting with a "/"). The origin of the
|
||||
absolute path name is the root of the tree that contains this VectorNode. If this VectorNode is not
|
||||
attached to an ImageFile, the @a pathName origin root will not the root node of an ImageFile.
|
||||
|
||||
The element names of child elements of VectorNodes are numbers, encoded as strings, starting at "0".
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return true if pathName is currently defined.
|
||||
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StructureNode::isDefined
|
||||
*/
|
||||
bool VectorNode::isDefined( const ustring &pathName ) const
|
||||
{
|
||||
return impl_->isDefined( pathName );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get a child element by positional index.
|
||||
|
||||
@param [in] index The index of child element to get, starting at 0.
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@pre 0 <= @a index < childCount()
|
||||
@post No visible state is modified.
|
||||
|
||||
@return A smart Node handle referencing the child node.
|
||||
|
||||
@throw ::ErrorChildIndexOutOfBounds
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see VectorNode::childCount, VectorNode::append, StructureNode::get(int64_t) const
|
||||
*/
|
||||
Node VectorNode::get( int64_t index ) const
|
||||
{
|
||||
return Node( impl_->get( index ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get a child element by string path name
|
||||
|
||||
@param [in] pathName The pathname, either absolute or relative, of the object to get.
|
||||
|
||||
@details
|
||||
The @a pathName may be relative to this node, or absolute (starting with a "/"). The origin of the
|
||||
absolute path name is the root of the tree that contains this VectorNode. If this VectorNode is not
|
||||
attached to an ImageFile, the @a pathName origin root will not the root node of an ImageFile.
|
||||
|
||||
The element names of child elements of VectorNodes are numbers, encoded as strings, starting at "0".
|
||||
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@pre The @a pathName must be defined (i.e. isDefined(pathName)).
|
||||
@post No visible state is modified.
|
||||
|
||||
@return A smart Node handle referencing the child node.
|
||||
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see VectorNode::childCount, VectorNode::append, StructureNode::get(int64_t) const
|
||||
*/
|
||||
Node VectorNode::get( const ustring &pathName ) const
|
||||
{
|
||||
return Node( impl_->get( pathName ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Append a child element to end of VectorNode.
|
||||
|
||||
@param [in] n The node to be added as a child at end of the VectorNode.
|
||||
|
||||
@details
|
||||
If the VectorNode is homogeneous and already has at least one child, then @a n must be identical to
|
||||
the existing children in every visible characteristic except the stored values. These visible
|
||||
characteristics include number of children (for StructureNode and VectorNode descendents), number of
|
||||
records/prototypes/codecs (for CompressedVectorNode), minimum/maximum attributes (for IntegerNode,
|
||||
ScaledIntegerNode, FloatNode), byteCount (for BlobNode), scale/offset (for ScaledIntegerNode), and
|
||||
all elementNames.
|
||||
|
||||
The VectorNode must not be a descendent of a homogeneous VectorNode with more than one child.
|
||||
|
||||
@pre The new child node @a n must be a root node (not already having a parent).
|
||||
@pre The destination ImageFile must be open (i.e. destImageFile().isOpen()).
|
||||
@pre The associated destImageFile must have been opened in write mode (i.e.
|
||||
destImageFile().isWritable()).
|
||||
@post the childCount is incremented.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorHomogeneousViolation
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorAlreadyHasParent
|
||||
@throw ::ErrorDifferentDestImageFile
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see VectorNode::childCount, VectorNode::get(int64_t), StructureNode::set
|
||||
*/
|
||||
void VectorNode::append( const Node &n )
|
||||
{
|
||||
impl_->append( n.impl() );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Diagnostic function to print internal state of object to output stream in an indented format.
|
||||
@copydetails Node::dump()
|
||||
*/
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void VectorNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
impl_->dump( indent, os );
|
||||
}
|
||||
#else
|
||||
void VectorNode::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
E57_UNUSED( indent );
|
||||
E57_UNUSED( os );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Upcast a VectorNode handle to a generic Node handle.
|
||||
|
||||
@details
|
||||
An upcast is always safe, and the compiler can automatically insert it for initializations of Node
|
||||
variables and Node function arguments.
|
||||
|
||||
@return A smart Node handle referencing the underlying object.
|
||||
|
||||
@throw No E57Exceptions.
|
||||
|
||||
@see explanation in Node, Node::type(), VectorNode(const Node&)
|
||||
*/
|
||||
VectorNode::operator Node() const
|
||||
{
|
||||
// Implicitly upcast from shared_ptr<VectorNodeImpl> to SharedNodeImplPtr and construct a Node
|
||||
// object
|
||||
return Node( impl_ );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Downcast a generic Node handle to a VectorNode handle.
|
||||
|
||||
@param [in] n The generic handle to downcast.
|
||||
|
||||
@details
|
||||
The handle @a n must be for an underlying VectorNode, otherwise an exception is thrown. In designs
|
||||
that need to avoid the exception, use Node::type() to determine the actual type of the @a n before
|
||||
downcasting. This function must be explicitly called (c++ compiler cannot insert it automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
|
||||
@see Node::type(), VectorNode::operator Node()
|
||||
*/
|
||||
VectorNode::VectorNode( const Node &n )
|
||||
{
|
||||
if ( n.type() != TypeVector )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorBadNodeDowncast, "nodeType=" + toString( n.type() ) );
|
||||
}
|
||||
|
||||
// Set our shared_ptr to the downcast shared_ptr
|
||||
impl_ = std::static_pointer_cast<VectorNodeImpl>( n.impl() );
|
||||
}
|
||||
|
||||
/// @cond documentNonPublic The following isn't part of the API, and isn't documented.
|
||||
VectorNode::VectorNode( std::shared_ptr<VectorNodeImpl> ni ) : impl_( ni )
|
||||
{
|
||||
}
|
||||
/// @endcond
|
||||
40
src/3rdParty/libE57Format/src/VectorNodeImpl.cpp
vendored
40
src/3rdParty/libE57Format/src/VectorNodeImpl.cpp
vendored
@@ -27,40 +27,41 @@
|
||||
|
||||
#include "VectorNodeImpl.h"
|
||||
#include "CheckedFile.h"
|
||||
#include "StringFunctions.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
VectorNodeImpl::VectorNodeImpl( ImageFileImplWeakPtr destImageFile, bool allowHeteroChildren ) :
|
||||
StructureNodeImpl( destImageFile ), allowHeteroChildren_( allowHeteroChildren )
|
||||
{
|
||||
/// don't checkImageFileOpen, StructNodeImpl() will do it
|
||||
// don't checkImageFileOpen, StructNodeImpl() will do it
|
||||
}
|
||||
|
||||
bool VectorNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
|
||||
/// Same node type?
|
||||
if ( ni->type() != E57_VECTOR )
|
||||
// Same node type?
|
||||
if ( ni->type() != TypeVector )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
std::shared_ptr<VectorNodeImpl> ai( std::static_pointer_cast<VectorNodeImpl>( ni ) );
|
||||
|
||||
/// allowHeteroChildren must match
|
||||
// allowHeteroChildren must match
|
||||
if ( allowHeteroChildren_ != ai->allowHeteroChildren_ )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// Same number of children?
|
||||
// Same number of children?
|
||||
if ( childCount() != ai->childCount() )
|
||||
{
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/// Check each child, must be in same order
|
||||
// Check each child, must be in same order
|
||||
for ( unsigned i = 0; i < childCount(); i++ )
|
||||
{
|
||||
if ( !children_.at( i )->isTypeEquivalent( ai->children_.at( i ) ) )
|
||||
@@ -69,7 +70,7 @@ namespace e57
|
||||
}
|
||||
}
|
||||
|
||||
/// Types match
|
||||
// Types match
|
||||
return ( true );
|
||||
}
|
||||
|
||||
@@ -84,26 +85,28 @@ namespace e57
|
||||
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
|
||||
if ( !allowHeteroChildren_ )
|
||||
{
|
||||
/// New node type must match all existing children
|
||||
// New node type must match all existing children
|
||||
for ( auto &child : children_ )
|
||||
{
|
||||
if ( !child->isTypeEquivalent( ni ) )
|
||||
{
|
||||
throw E57_EXCEPTION2( E57_ERROR_HOMOGENEOUS_VIOLATION, "this->pathName=" + this->pathName() );
|
||||
throw E57_EXCEPTION2( ErrorHomogeneousViolation,
|
||||
"this->pathName=" + this->pathName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///??? for now, use base implementation
|
||||
//??? for now, use base implementation
|
||||
StructureNodeImpl::set( index64, ni );
|
||||
}
|
||||
|
||||
void VectorNodeImpl::writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent, const char *forcedFieldName )
|
||||
void VectorNodeImpl::writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
|
||||
const char *forcedFieldName )
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
// don't checkImageFileOpen
|
||||
|
||||
ustring fieldName;
|
||||
if ( forcedFieldName )
|
||||
if ( forcedFieldName != nullptr )
|
||||
{
|
||||
fieldName = forcedFieldName;
|
||||
}
|
||||
@@ -121,13 +124,12 @@ namespace e57
|
||||
cf << space( indent ) << "</" << fieldName << ">\n";
|
||||
}
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void VectorNodeImpl::dump( int indent, std::ostream &os ) const
|
||||
{
|
||||
/// don't checkImageFileOpen
|
||||
os << space( indent ) << "type: Vector"
|
||||
<< " (" << type() << ")" << std::endl;
|
||||
NodeImpl::dump( indent, os );
|
||||
// don't checkImageFileOpen
|
||||
os << space( indent ) << "type: Vector" << " (" << type() << ")" << std::endl;
|
||||
NodeImpl::dump( indent, os ); // NOLINT(bugprone-parent-virtual-call)
|
||||
os << space( indent ) << "allowHeteroChildren: " << allowHeteroChildren() << std::endl;
|
||||
for ( unsigned i = 0; i < children_.size(); i++ )
|
||||
{
|
||||
|
||||
11
src/3rdParty/libE57Format/src/VectorNodeImpl.h
vendored
11
src/3rdParty/libE57Format/src/VectorNodeImpl.h
vendored
@@ -33,12 +33,12 @@ namespace e57
|
||||
class VectorNodeImpl : public StructureNodeImpl
|
||||
{
|
||||
public:
|
||||
explicit VectorNodeImpl( ImageFileImplWeakPtr destImageFile, bool allowHeteroChildren );
|
||||
VectorNodeImpl( ImageFileImplWeakPtr destImageFile, bool allowHeteroChildren );
|
||||
~VectorNodeImpl() override = default;
|
||||
|
||||
NodeType type() const override
|
||||
{
|
||||
return E57_VECTOR;
|
||||
return TypeVector;
|
||||
}
|
||||
|
||||
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
|
||||
@@ -49,11 +49,16 @@ namespace e57
|
||||
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
|
||||
const char *forcedFieldName = nullptr ) override;
|
||||
|
||||
#ifdef E57_DEBUG
|
||||
#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
|
||||
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Because we are overriding set(), it is hiding the other overrides in StructureNodeImpl.
|
||||
// This will pull them in.
|
||||
// Fixes the "overloaded-virtual" warning in gcc.
|
||||
using StructureNodeImpl::set;
|
||||
|
||||
bool allowHeteroChildren_;
|
||||
};
|
||||
}
|
||||
|
||||
1127
src/3rdParty/libE57Format/src/WriterImpl.cpp
vendored
1127
src/3rdParty/libE57Format/src/WriterImpl.cpp
vendored
File diff suppressed because it is too large
Load Diff
30
src/3rdParty/libE57Format/src/WriterImpl.h
vendored
30
src/3rdParty/libE57Format/src/WriterImpl.h
vendored
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
|
||||
* Copyright (c) 2020 PTC Inc.
|
||||
* Copyright (c) 2022 Andy Maloney <asmaloney@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
@@ -28,26 +29,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "E57SimpleData.h"
|
||||
#include "E57SimpleWriter.h"
|
||||
|
||||
namespace e57
|
||||
{
|
||||
|
||||
//! most of the functions follows Writer
|
||||
class WriterImpl
|
||||
{
|
||||
public:
|
||||
WriterImpl( const ustring &filePath, const ustring &coordinateMetaData );
|
||||
|
||||
WriterImpl( const ustring &filePath, const WriterOptions &options );
|
||||
~WriterImpl();
|
||||
|
||||
// disallow copying a WriterImpl
|
||||
WriterImpl( const WriterImpl & ) = delete;
|
||||
WriterImpl &operator=( WriterImpl const & ) = delete;
|
||||
WriterImpl( const WriterImpl && ) = delete;
|
||||
WriterImpl &operator=( const WriterImpl && ) = delete;
|
||||
|
||||
bool IsOpen() const;
|
||||
|
||||
bool Close();
|
||||
|
||||
int64_t NewImage2D( Image2D &image2DHeader );
|
||||
|
||||
int64_t WriteImage2DData( int64_t imageIndex, Image2DType imageType, Image2DProjection imageProjection,
|
||||
void *pBuffer, int64_t start, int64_t count );
|
||||
size_t WriteImage2DData( int64_t imageIndex, Image2DType imageType,
|
||||
Image2DProjection imageProjection, uint8_t *pBuffer, int64_t start,
|
||||
size_t count );
|
||||
|
||||
int64_t NewData3D( Data3D &data3DHeader );
|
||||
|
||||
@@ -55,7 +61,7 @@ namespace e57
|
||||
CompressedVectorWriter SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
|
||||
const Data3DPointsData_t<COORDTYPE> &buffers );
|
||||
|
||||
bool WriteData3DGroupsData( int64_t dataIndex, int64_t groupCount, int64_t *idElementValue,
|
||||
bool WriteData3DGroupsData( int64_t dataIndex, size_t groupCount, int64_t *idElementValue,
|
||||
int64_t *startPointIndex, int64_t *pointCount );
|
||||
|
||||
StructureNode GetRawE57Root();
|
||||
@@ -73,15 +79,5 @@ namespace e57
|
||||
VectorNode data3D_;
|
||||
|
||||
VectorNode images2D_;
|
||||
|
||||
//! @brief This function writes the projection image
|
||||
//! @param image 1 of 3 projects or the visual
|
||||
//! @param imageType identifies the image format desired.
|
||||
//! @param pBuffer pointer the buffer
|
||||
//! @param start position in the block to start reading
|
||||
//! @param count size of desired chuck or buffer size
|
||||
int64_t WriteImage2DNode( StructureNode image, Image2DType imageType, void *pBuffer, int64_t start,
|
||||
int64_t count );
|
||||
}; // end Writer class
|
||||
|
||||
} // end namespace e57
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user