3rdParty: Remove original libE57Format

This commit is contained in:
Chris Hennes
2025-09-23 14:17:47 -05:00
parent e9ce06155d
commit 11f6f498ab
77 changed files with 0 additions and 25270 deletions

View File

@@ -1,108 +0,0 @@
# libE57Format
# Options are listed here:
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
---
AccessModifierOffset: -3
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 3
ContinuationIndentWidth: 3
Cpp11BracedListStyle: false
DerivePointerAlignment: false
FixNamespaceComments: false
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
IndentWrappedFunctionNames: true
KeepEmptyLinesAtTheStartOfBlocks: true
Language: Cpp
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: true
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 3
UseTab: Never
...

View File

@@ -1 +0,0 @@
extern/*

View File

@@ -1 +0,0 @@
github: [asmaloney]

View File

@@ -1,82 +0,0 @@
name: Build
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,
}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install Dependencies (macOS)
if: matrix.config.os == 'macos-latest'
run: |
brew install ninja xerces-c
- name: Install Dependencies (Ubuntu)
if: matrix.config.os == 'ubuntu-latest'
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'
- name: Install Dependencies (Windows)
if: matrix.config.os == 'windows-latest'
run: |
conda install -y ninja xerces-c
- name: Configure MSVC console (Windows)
if: matrix.config.os == 'windows-latest'
uses: ilammy/msvc-dev-cmd@v1
- name: Set environment for MSVC (Windows)
if: matrix.config.os == 'windows-latest'
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
- name: Configure
run: >
mkdir libE57Format-build
cmake
-B libE57Format-build
-G "Ninja"
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-DCMAKE_CXX_FLAGS_DEBUG="-g -DE57_MAX_VERBOSE"
.
- name: Build
run: |
cmake --build libE57Format-build

File diff suppressed because one or more lines are too long

View File

@@ -1,103 +0,0 @@
# Changelog
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/).
## 2.2.1 - (in progress)
### Fixed
- 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!)
## [2.2.0](https://github.com/asmaloney/libE57Format/releases/tag/v2.2.0) - 2021-04-01
### Added
- Added and updated the E57Simple API from the old reference library. ([#41](https://github.com/asmaloney/libE57Format/pull/41), [#63](https://github.com/asmaloney/libE57Format/pull/63)) (Thanks Jiri & Grégoire!)
- Enabled building E57Format as a shared library. ([#40](https://github.com/asmaloney/libE57Format/pull/40)) (Thanks Amodio!)
- Added a [clang-format](https://clang.llvm.org/docs/ClangFormat.html) file, a cmake target for it ("format"), and reformatted the code.
- {doc} Added info about using [SPDX License Identifiers](https://spdx.org/ids).
- {ci} Added GitHub Actions to build macOS, Linux, and Windows. ([#35](https://github.com/asmaloney/libE57Format/pull/35))
### Changed
- `E57_V1_0_URI` was changed from a `#define` to a `constexpr`, so if you use it, it will need to be updated with a namespace: `e57::E57_V1_0_URI`.
- {doc} Moved some documentation to new repo ([libE57Format-docs](https://github.com/asmaloney/libE57Format-docs)) and generate the [docs](https://asmaloney.github.io/libE57Format-docs/).
- {cmake} Reviewed and updated cmake files. CMake minimum version was changed to 3.10.
### Fixed
- Fixed building with E57_MAX_VERBOSE defined. ([#44](https://github.com/asmaloney/libE57Format/pull/44))
- {win} Fixed MSVC warnings. ([#34](https://github.com/asmaloney/libE57Format/pull/34), [#36](https://github.com/asmaloney/libE57Format/pull/36))
### 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.
## [2.1.0](https://github.com/asmaloney/libE57Format/releases/tag/v2.1) - 2020-04-01
### Added
- Added support for UTF8 file names on Windows. (based on [#26](https://github.com/asmaloney/libE57Format/issues/26))
- Added support for _char\*_ input. ([#22](https://github.com/asmaloney/libE57Format/pull/22))
- {cmake} Added fallback configuration for RelWithDebInfo and MinSizeRel. ([#29](https://github.com/asmaloney/libE57Format/pull/29))
- {cmake} Added a proper install configuration. ([#28](https://github.com/asmaloney/libE57Format/pull/28))
### Changed
- {cmake} Removed unused ICU requirement for Linux.
### Fixed
- {cmake} Marked xerces-c as required.
### Other
- {cmake} Various cleanups.
- Internal code cleanups.
## [2.0.1](https://github.com/asmaloney/libE57Format/releases/tag/v2.0.1) - 2019-01-15
### Fixed
- Writing files was broken and would produce the following error:
> Error: bad API function argument provided by user (E57_ERROR_BAD_API_ARGUMENT) (ImageFileImpl.cpp line 109)
## [2.0.0](https://github.com/asmaloney/libE57Format/releases/tag/v2.0) - 2019-01-06
Forked from [E57RefImpl](https://sourceforge.net/projects/e57-3d-imgfmt/).
### Added
- Added a checksum policy (see _ReadChecksumPolicy_ in _E57Format.h_) so the library user can decide how frequently to check them.
- {win} Added cmake option ()`USING_STATIC_XERCES`) to tell the build if you are using a static Xerces lib.
### Changed
- Now requires C++11.
- Now requires cmake 3.1+.
- No longer uses BOOST.
- Turn off `E57_MAX_DEBUG` by default.
### Removed
- Removed all but the main sources for reading and writing E57 files.
- Removed "big endian" byte swap code (not sure it was working and no way to test).
### Fixed
- Multiple fixes for compilation on macOS.
- Fixed a couple of fallthrough bugs which would result in undefined behaviour.
### Other
- Improved file read times.
- Many, many code cleanups:
- Refactored the code into multiple files.
- Removed unused macros and code.
- Removed non-useful comments.
- Added proper initialization of class and struct members.
- Modernized using c++11.

View File

@@ -1,206 +0,0 @@
# This is a rewrite over time of the CMake file from the libe57 reference implementation
# https://en.wikipedia.org/wiki/Ship_of_Theseus
#
# Use git blame to see all the changes and who has contributed.
#
# 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
# 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.
cmake_minimum_required( VERSION 3.10.0 )
# Set a private module find path
set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/" )
project( E57Format
DESCRIPTION
"E57Format is a library to read and write E57 files"
LANGUAGES
CXX
VERSION
2.2.1
)
include( Tags )
# Check if we are building ourself or being included and use this to set some defaults
if ( ${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME} )
set( E57_BUILDING_SELF ON )
endif()
# propose a default installation directory
if ( E57_BUILDING_SELF )
if( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
string( REGEX REPLACE "/${PROJECT_NAME}" "" CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} )
set( T_ ${PROJECT_NAME} )
set( T_ ${T_}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} )
set( T_ ${T_}-${${PROJECT_NAME}_BUILD_TAG} )
set( CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${T_}
CACHE PATH
"Install path prefix, prepended onto install directories."
FORCE
)
endif()
endif()
find_package( Threads REQUIRED )
find_package( XercesC REQUIRED )
option( E57_BUILD_SHARED
"Compile E57Format as a shared library"
OFF
)
if( BUILD_SHARED_LIBS )
set( E57_BUILD_SHARED ON )
endif()
#########################################################################################
# Various levels of cross checking and verification in the code.
# The extra code does not change the file contents.
# Recommend that E57_DEBUG remain defined even for production versions.
option( E57_DEBUG "Compile library with minimal debug checking" ON )
option( E57_MAX_DEBUG "Compile library with maximum debug checking" 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 writing packets that are correct but will stress the reader.
option( E57_WRITE_CRAZY_PACKET_MODE "Compile library to enable reader-stressing packets" OFF )
#########################################################################################
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)
endif()
# Target
if ( E57_BUILD_SHARED )
message( STATUS "[E57] Building shared library" )
add_library( E57Format SHARED ${E57Format_SOURCES})
else()
message( STATUS "[E57] Building static library" )
add_library( E57Format STATIC ${E57Format_SOURCES})
endif()
include( E57ExportHeader )
# 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"
POSITION_INDEPENDENT_CODE ON
)
# Target definitions
target_compile_definitions( E57Format
PRIVATE
CRCPP_USE_CPP11
CRCPP_BRANCHLESS
REVISION_ID="${revision_id}"
)
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>
)
# Target Libraries
target_link_libraries( E57Format PRIVATE XercesC::XercesC )
# Install
install(
TARGETS
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
#)
#install(
# FILES
# ${CMAKE_CURRENT_SOURCE_DIR}/cmake/e57format-config.cmake
# DESTINATION
# lib/cmake/E57Format
#)

View File

@@ -1,21 +0,0 @@
# How To Contribute
## Code Changes
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.
### 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:
```sh
cmake --build . --target 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.
## 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.

View File

@@ -1,23 +0,0 @@
Boost Software License - Version 1.0 - August 17th, 2003
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.

View File

@@ -1,53 +0,0 @@
# libE57Format
[![Build Status](https://travis-ci.org/asmaloney/libE57Format.svg?branch=master)](https://travis-ci.org/asmaloney/libE57Format)
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.
## 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
Please see [CONTRIBUTING](CONTRIBUTING.md).
## Why Fork?
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.
I changed the name of the project so that it is not confused with the **E57RefImpl** project.
I have also 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.
### 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.
### Tools
[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.
## 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.
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.

View File

@@ -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()

View File

@@ -1,38 +0,0 @@
# SPDX-License-Identifier: MIT
# 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." )
generate_export_header( E57Format
EXPORT_FILE_NAME E57Export.h
EXPORT_MACRO_NAME E57_DLL
CUSTOM_CONTENT_FROM_VARIABLE comment
)
unset( comment )
target_sources( E57Format
PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/E57Export.h
)
target_include_directories( ${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
)
target_compile_definitions( E57Format
PRIVATE
$<$<BOOL:E57_BUILD_SHARED>:E57Format_EXPORTS>
)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/E57Export.h
DESTINATION
include/E57Format
)

View File

@@ -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_})

View File

@@ -1,9 +0,0 @@
include(CMakeFindDependencyMacro)
find_dependency(XercesC REQUIRED)
include(${CMAKE_CURRENT_LIST_DIR}/E57Format-export.cmake)
set_target_properties(E57Format PROPERTIES
MAP_IMPORTED_CONFIG_MINSIZEREL "MinSizeRel;Release"
MAP_IMPORTED_CONFIG_RELWITHDEBINFO "RelWithDebInfo;Release"
)

View File

@@ -1,14 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright © Andy Maloney <asmaloney@gmail.com>
# CRCpp from here: https://github.com/d-bahr/CRCpp
target_sources( ${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/inc/CRC.h
)
target_include_directories( ${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/inc
)

View File

@@ -1,28 +0,0 @@
CRC++
Copyright (c) 2016, Daniel Bahr
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of CRC++ nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,154 +0,0 @@
# CRC++
Easy to use and fast C++ CRC library.
Tired of writing CRC code over and over again? Don't want to include a dozen boost header files just for a little bit of functionality? CRC++ is a portable and extremely lightweight alternative that is incredibly simple, fast, and clean.
### Features
CRC++ supports bit-by-bit and byte-by-byte calculation of full and multipart CRCs. The algorithms used are highly optimized and can even be configured to be branchless (as always, be sure to profile your code to choose the most efficient option). CRC++ is a great option for embedded C++ projects with a need for efficiency.
CRC++ consists of a single header file which can be included in any existing C++ application. No libraries, no boost, no mess, no fuss.
Any CRC width is supported - even CRCs larger than 64 bits, provided there is an integer type large enough to contain it. Trying to compute a 57-bit CRC? Got you covered.
Many common CRCs are provided out-of-the-box, such as CRC-32 (used in PKZip and Ethernet), CRC-XMODEM, and CRC-CCITT.
CRC++ will compile with any reasonably compliant C++03 or C++11 compiler. Compiling with C++11 is recommended, as it allows a number of static computations to be performed at compile-time instead of runtime.
All of the CRC++ code is well-documented. Unit tests are included in the repository (g++ Makefile and Visual Studio 2015 projects included). HTML documentation can also be produced via Doxygen (also included in the repository).
### Comparison
CRC++ boasts one of the fastest and most memory efficient generic CRC implementation available. The below table shows performance comparisons across multiple implementations and platforms.
| Library | Speed, x64 platform (100 million iterations) | Speed, x86 platform (100 million iterations) |
| ------------- | -------------------------------------------- | -------------------------------------------- |
| CRC++ | 2050 milliseconds | 2200 milliseconds |
| boost | 2250 milliseconds | 2000 milliseconds |
| pycrc | 2050 milliseconds | 2240 milliseconds |
| mhash | 2250 milliseconds | 2400 milliseconds |
Additionally, CRC++ has the most features of any library and the smallest code footprint:
| Library | Number of include files | Header-only implemen-tation | Supports byte != 8 bits | Supports arbitrary CRC width | Custom type support | C++11 support | 40+ built-in CRC definitions | Branchless implemen-tation |
| ------------- | ----------------------- | --------------------------- | ----------------------- | ---------------------------- | ------------------- | ------------- | ---------------------------- | -------------------------- |
| CRC++ | 1 | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| boost | 17 | Yes | Yes | Yes | Yes | Yes | No | No |
| pycrc | 2 per CRC algorithm | No | No | No | No | No | No | No |
| mhash | 6 | No | Yes | No | No | No | No | No |
### Usage
Computing a CRC is as simple as the following code:
```cpp
#include "CRC.h" // Only need to include this header file!
// No libraries need to be included. No project settings need to be messed with.
#include <iomanip> // Includes ::std::hex
#include <iostream> // Includes ::std::cout
#include <cstdint> // Includes ::std::uint32_t
int main(int argc, char ** argv)
{
const char myString[] = { 'H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D' };
std::uint32_t crc = CRC::Calculate(myString, sizeof(myString), CRC::CRC_32());
std::cout << std::hex << crc;
return 0;
}
```
Multi-part CRCs are also supported:
```cpp
int main(int argc, char ** argv)
{
const char myHelloString[] = { 'H', 'E', 'L', 'L', 'O', ' ' };
const char myWorldString[] = { 'W', 'O', 'R', 'L', 'D' };
std::uint32_t crc;
crc = CRC::Calculate(myHelloString, sizeof(myHelloString), CRC::CRC_32());
crc = CRC::Calculate(myWorldString, sizeof(myWorldString), CRC::CRC_32(), crc);
std::cout << std::hex << crc;
return 0;
}
```
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:
```cpp
int main(int argc, char ** argv)
{
const char myHelloString[] = { 'H', 'E', 'L', 'L', 'O', ' ' };
const char myWorldString[] = { 'W', 'O', 'R', 'L', 'D' };
CRC::Table<std::uint32_t, 32> table(CRC::CRC_32());
std::uint32_t crc;
crc = CRC::Calculate(myHelloString, sizeof(myHelloString), table);
crc = CRC::Calculate(myWorldString, sizeof(myWorldString), table, crc);
std::cout << std::hex << crc;
return 0;
}
```
Or, if you prefer using the `auto` keyword:
```cpp
int main(int argc, char ** argv)
{
const char myHelloString[] = { 'H', 'E', 'L', 'L', 'O', ' ' };
const char myWorldString[] = { 'W', 'O', 'R', 'L', 'D' };
auto table = CRC::CRC_32().MakeTable();
std::uint32_t crc;
crc = CRC::Calculate(myHelloString, sizeof(myHelloString), table);
crc = CRC::Calculate(myWorldString, sizeof(myWorldString), table, crc);
std::cout << std::hex << crc;
return 0;
}
```
Lookup tables are much faster than computing a CRC bit-by-bit, at the expense of extra memory usage. A lookup table can be reused for as many CRCs as desired until it goes out of scope.
### Configuration
CRC++ can be configured by setting various `#define`s before `#include`-ing the CRC++ header file:
* `#define crcpp_uint8`<br>
Specifies the type used to store CRCs that have a width of 8 bits or less. This type is not used in CRC calculations. Defaults to ::std::uint8_t.
* `#define crcpp_uint16`<br>
Specifies the type used to store CRCs that have a width between 9 and 16 bits (inclusive). This type is not used in CRC calculations. Defaults to ::std::uint16_t.
* `#define crcpp_uint32`<br>
Specifies the type used to store CRCs that have a width between 17 and 32 bits (inclusive). This type is not used in CRC calculations. Defaults to ::std::uint32_t.
* `#define crcpp_uint64`<br>
Specifies the type used to store CRCs that have a width between 33 and 64 bits (inclusive). This type is not used in CRC calculations. Defaults to ::std::uint64_t.
* `#define crcpp_size`<br>
This type is used for loop iteration and function signatures only. Defaults to ::std::size_t.
* `#define CRCPP_USE_NAMESPACE`<br>
Define to place all CRC++ code within the ::CRCPP namespace. Not defined by default.
* `#define CRCPP_BRANCHLESS`<br>
Define to enable a branchless CRC implementation. The branchless implementation uses a single integer 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. Not defined by default.
* `#define CRCPP_USE_CPP11`
Define to enables C++11 features (move semantics, constexpr, static_assert, etc.). Not defined by default.
* `#define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS`
Define to include definitions for little-used CRCs. Not defined by default.
### License
CRC++ is free to use and provided under a BSD license.

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +0,0 @@
# SPDX-License-Identifier: MIT
# 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
)
#install(
# FILES
# E57Format.h
# E57Exception.h
# E57SimpleData.h
# E57SimpleReader.h
# E57SimpleWriter.h
# DESTINATION
# include/E57Format
#)
target_include_directories( ${PROJECT_NAME}
SYSTEM PUBLIC
$<INSTALL_INTERFACE:include/E57Format>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)

View File

@@ -1,136 +0,0 @@
/*
* 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 <exception>
#include <iostream>
#include <string>
#include "E57Export.h"
namespace e57
{
//! @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
};
class E57_DLL E57Exception : public std::exception
{
public:
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;
// For debugging purposes:
const char *sourceFileName() const;
const char *sourceFunctionName() const;
int sourceLineNumber() const;
//! \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;
protected:
ErrorCode errorCode_;
std::string context_;
std::string sourceFileName_;
const char *sourceFunctionName_;
int sourceLineNumber_;
//! \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 );
}
}

View File

@@ -1,697 +0,0 @@
/*
* E57Format.h - public header of E57 API for reading/writing .e57 files.
*
* 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
//! @file E57Format.h header file for the E57 API
#include <cfloat>
#include <memory>
#include <cstdint>
#include <vector>
#include "E57Exception.h"
namespace e57
{
using std::int16_t;
using std::int32_t;
using std::int64_t;
using std::int8_t;
using std::uint16_t;
using std::uint32_t;
using std::uint64_t;
using std::uint8_t;
// Shorthand for unicode string
//! @brief UTF-8 encodeded Unicode string
using ustring = std::string;
//! @brief Identifiers for types of E57 elements
enum NodeType
{
E57_STRUCTURE = 1, //!< StructureNode class
E57_VECTOR = 2, //!< VectorNode class
E57_COMPRESSED_VECTOR = 3, //!< CompressedVectorNode class
E57_INTEGER = 4, //!< IntegerNode class
E57_SCALED_INTEGER = 5, //!< ScaledIntegerNode class
E57_FLOAT = 6, //!< FloatNode class
E57_STRING = 7, //!< StringNode class
E57_BLOB = 8 //!< BlobNode class
};
//! @brief The IEEE floating point number precisions supported
enum FloatPrecision
{
E57_SINGLE = 1, //!< 32 bit IEEE floating point number format
E57_DOUBLE = 2 //!< 64 bit IEEE floating point number format
};
//! @brief Identifies the representations of memory elements API can transfer
//! data to/from
enum MemoryRepresentation
{
E57_INT8 = 1, //!< 8 bit signed integer
E57_UINT8 = 2, //!< 8 bit unsigned integer
E57_INT16 = 3, //!< 16 bit signed integer
E57_UINT16 = 4, //!< 16 bit unsigned integer
E57_INT32 = 5, //!< 32 bit signed integer
E57_UINT32 = 6, //!< 32 bit unsigned integer
E57_INT64 = 7, //!< 64 bit signed integer
E57_BOOL = 8, //!< C++ boolean type
E57_REAL32 = 9, //!< C++ float type
E57_REAL64 = 10, //!< C++ double type
E57_USTRING = 11 //!< Unicode UTF-8 std::string
};
//! @brief Specifies the percentage of checksums which are verified when reading
//! an ImageFile (0-100%).
using ReadChecksumPolicy = int;
//! Do not verify the checksums. (fast)
constexpr ReadChecksumPolicy CHECKSUM_POLICY_NONE = 0;
//! Only verify 25% of the checksums. The last block is always verified.
constexpr ReadChecksumPolicy CHECKSUM_POLICY_SPARSE = 25;
//! Only verify 50% of the checksums. The last block is always verified.
constexpr ReadChecksumPolicy CHECKSUM_POLICY_HALF = 50;
//! Verify all checksums. This is the default. (slow)
constexpr ReadChecksumPolicy CHECKSUM_POLICY_ALL = 100;
//! @brief The URI of ASTM E57 v1.0 standard XML namespace
//! Note that even though this URI does not point to a valid document, the standard (section 8.4.2.3)
//! says that this is the required namespace.
constexpr char E57_V1_0_URI[] = "http://www.astm.org/COMMIT/E57/2010-e57-v1.0";
//! @cond documentNonPublic The following aren't documented
// Minimum and maximum values for integers
constexpr int8_t E57_INT8_MIN = -128;
constexpr int8_t E57_INT8_MAX = 127;
constexpr int16_t E57_INT16_MIN = -32768;
constexpr int16_t E57_INT16_MAX = 32767;
constexpr int32_t E57_INT32_MIN = -2147483647 - 1;
constexpr int32_t E57_INT32_MAX = 2147483647;
constexpr int64_t E57_INT64_MIN = -9223372036854775807LL - 1;
constexpr int64_t E57_INT64_MAX = 9223372036854775807LL;
constexpr uint8_t E57_UINT8_MIN = 0U;
constexpr uint8_t E57_UINT8_MAX = 0xffU; /* 255U */
constexpr uint16_t E57_UINT16_MIN = 0U;
constexpr uint16_t E57_UINT16_MAX = 0xffffU; /* 65535U */
constexpr uint32_t E57_UINT32_MIN = 0U;
constexpr uint32_t E57_UINT32_MAX = 0xffffffffU; /* 4294967295U */
constexpr uint64_t E57_UINT64_MIN = 0ULL;
constexpr uint64_t E57_UINT64_MAX = 0xffffffffffffffffULL; /* 18446744073709551615ULL */
constexpr float E57_FLOAT_MIN = -FLT_MAX;
constexpr float E57_FLOAT_MAX = FLT_MAX;
constexpr double E57_DOUBLE_MIN = -DBL_MAX;
constexpr double E57_DOUBLE_MAX = DBL_MAX;
//! @endcond
//! @cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
// Internal implementation files should include E57FormatImpl.h first which
// defines symbol E57_INTERNAL_IMPLEMENTATION_ENABLE. Normal API users should
// not define this symbol. Basically the internal version allows access to the
// pointer to the implementation (impl_)
#ifdef E57_INTERNAL_IMPLEMENTATION_ENABLE
#define E57_OBJECT_IMPLEMENTATION( T ) \
public: \
std::shared_ptr<T##Impl> impl() const \
{ \
return ( impl_ ); \
} \
\
protected: \
std::shared_ptr<T##Impl> impl_;
#else
#define E57_OBJECT_IMPLEMENTATION( T ) \
protected: \
std::shared_ptr<T##Impl> impl_;
#endif
//! @endcond
class BlobNode;
class BlobNodeImpl;
class CompressedVectorNode;
class CompressedVectorNodeImpl;
class CompressedVectorReader;
class CompressedVectorReaderImpl;
class CompressedVectorWriter;
class CompressedVectorWriterImpl;
class FloatNode;
class FloatNodeImpl;
class ImageFile;
class ImageFileImpl;
class IntegerNode;
class IntegerNodeImpl;
class Node;
class NodeImpl;
class ScaledIntegerNode;
class ScaledIntegerNodeImpl;
class SourceDestBuffer;
class SourceDestBufferImpl;
class StringNode;
class StringNodeImpl;
class StructureNode;
class StructureNodeImpl;
class VectorNode;
class VectorNodeImpl;
class E57_DLL Node
{
public:
Node() = delete;
NodeType type() const;
bool isRoot() const;
Node parent() const;
ustring pathName() const;
ustring elementName() const;
ImageFile destImageFile() const;
bool isAttached() const;
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true, bool doDowncast = true );
bool operator==( Node n2 ) const;
bool operator!=( Node n2 ) const;
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
#ifdef E57_INTERNAL_IMPLEMENTATION_ENABLE
explicit Node( std::shared_ptr<NodeImpl> ); // internal use only
#endif
private:
friend class NodeImpl;
E57_OBJECT_IMPLEMENTATION( Node ) // Internal implementation details, not
// part of API, must be last in object
//! \endcond
};
class E57_DLL StructureNode
{
public:
StructureNode() = delete;
StructureNode( ImageFile destImageFile );
int64_t childCount() const;
bool isDefined( const ustring &pathName ) const;
Node get( int64_t index ) const;
Node get( const ustring &pathName ) const;
void set( const ustring &pathName, const Node &n );
// Up/Down cast conversion
operator Node() const;
explicit StructureNode( const Node &n );
// Common generic Node functions
bool isRoot() const;
Node parent() const;
ustring pathName() const;
ustring elementName() const;
ImageFile destImageFile() const;
bool isAttached() const;
// Diagnostic functions:
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true, bool doUpcast = true );
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
friend class ImageFile;
StructureNode( std::shared_ptr<StructureNodeImpl> ni ); // internal use only
StructureNode( std::weak_ptr<ImageFileImpl> fileParent ); // internal use only
E57_OBJECT_IMPLEMENTATION( StructureNode ) // Internal implementation details, not part of API, must
// be last in object
//! \endcond
};
class E57_DLL VectorNode
{
public:
VectorNode() = delete;
explicit VectorNode( ImageFile destImageFile, bool allowHeteroChildren = false );
bool allowHeteroChildren() const;
int64_t childCount() const;
bool isDefined( const ustring &pathName ) const;
Node get( int64_t index ) const;
Node get( const ustring &pathName ) const;
void append( const Node &n );
// Up/Down cast conversion
operator Node() const;
explicit VectorNode( const Node &n );
// Common generic Node functions
bool isRoot() const;
Node parent() const;
ustring pathName() const;
ustring elementName() const;
ImageFile destImageFile() const;
bool isAttached() const;
// Diagnostic functions:
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true, bool doUpcast = true );
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
friend class CompressedVectorNode;
VectorNode( std::shared_ptr<VectorNodeImpl> ni ); // internal use only
E57_OBJECT_IMPLEMENTATION( VectorNode ) // Internal implementation details, not part of API, must be
// last in object
//! \endcond
};
class E57_DLL SourceDestBuffer
{
public:
SourceDestBuffer() = delete;
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, int8_t *b, const size_t capacity,
bool doConversion = false, bool doScaling = false, size_t stride = sizeof( int8_t ) );
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, uint8_t *b, const size_t capacity,
bool doConversion = false, bool doScaling = false, size_t stride = sizeof( uint8_t ) );
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, int16_t *b, const size_t capacity,
bool doConversion = false, bool doScaling = false, size_t stride = sizeof( int16_t ) );
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, uint16_t *b, const size_t capacity,
bool doConversion = false, bool doScaling = false, size_t stride = sizeof( uint16_t ) );
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, int32_t *b, const size_t capacity,
bool doConversion = false, bool doScaling = false, size_t stride = sizeof( int32_t ) );
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, uint32_t *b, const size_t capacity,
bool doConversion = false, bool doScaling = false, size_t stride = sizeof( uint32_t ) );
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, int64_t *b, const size_t capacity,
bool doConversion = false, bool doScaling = false, size_t stride = sizeof( int64_t ) );
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, bool *b, const size_t capacity,
bool doConversion = false, bool doScaling = false, size_t stride = sizeof( bool ) );
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, float *b, const size_t capacity,
bool doConversion = false, bool doScaling = false, size_t stride = sizeof( float ) );
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, double *b, const size_t capacity,
bool doConversion = false, bool doScaling = false, size_t stride = sizeof( double ) );
SourceDestBuffer( ImageFile destImageFile, const ustring &pathName, std::vector<ustring> *b );
ustring pathName() const;
enum MemoryRepresentation memoryRepresentation() const;
size_t capacity() const;
bool doConversion() const;
bool doScaling() const;
size_t stride() const;
// Diagnostic functions:
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true ) const;
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
E57_OBJECT_IMPLEMENTATION( SourceDestBuffer ) // Internal implementation details, not part of
// API, must be last in object
//! \endcond
};
class E57_DLL CompressedVectorReader
{
public:
CompressedVectorReader() = delete;
unsigned read();
unsigned read( std::vector<SourceDestBuffer> &dbufs );
void seek( int64_t recordNumber ); // !!! not implemented yet
void close();
bool isOpen();
CompressedVectorNode compressedVectorNode() const;
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true );
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
friend class CompressedVectorNode;
CompressedVectorReader( std::shared_ptr<CompressedVectorReaderImpl> ni );
E57_OBJECT_IMPLEMENTATION( CompressedVectorReader ) // Internal implementation details, not
// part of API, must be last in object
//! \endcond
};
class E57_DLL CompressedVectorWriter
{
public:
CompressedVectorWriter() = delete;
void write( const size_t recordCount );
void write( std::vector<SourceDestBuffer> &sbufs, const size_t recordCount );
void close();
bool isOpen();
CompressedVectorNode compressedVectorNode() const;
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true );
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
friend class CompressedVectorNode;
CompressedVectorWriter( std::shared_ptr<CompressedVectorWriterImpl> ni );
E57_OBJECT_IMPLEMENTATION( CompressedVectorWriter ) // Internal implementation details, not
// part of API, must be last in object
//! \endcond
};
class E57_DLL CompressedVectorNode
{
public:
CompressedVectorNode() = delete;
explicit CompressedVectorNode( ImageFile destImageFile, const Node &prototype, const VectorNode &codecs );
int64_t childCount() const;
Node prototype() const;
VectorNode codecs() const;
// Iterators
CompressedVectorWriter writer( std::vector<SourceDestBuffer> &sbufs );
CompressedVectorReader reader( const std::vector<SourceDestBuffer> &dbufs );
// Up/Down cast conversion
operator Node() const;
explicit CompressedVectorNode( const Node &n );
// Common generic Node functions
bool isRoot() const;
Node parent() const;
ustring pathName() const;
ustring elementName() const;
ImageFile destImageFile() const;
bool isAttached() const;
// Diagnostic functions:
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true, bool doUpcast = true );
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
friend class CompressedVectorReader;
friend class CompressedVectorWriter;
friend class E57XmlParser;
CompressedVectorNode( std::shared_ptr<CompressedVectorNodeImpl> ni ); // internal use only
E57_OBJECT_IMPLEMENTATION( CompressedVectorNode ) // Internal implementation details, not part
// of API, must be last in object
//! \endcond
};
class E57_DLL IntegerNode
{
public:
IntegerNode() = delete;
explicit IntegerNode( ImageFile destImageFile, int64_t value = 0, int64_t minimum = E57_INT64_MIN,
int64_t maximum = E57_INT64_MAX );
int64_t value() const;
int64_t minimum() const;
int64_t maximum() const;
// Up/Down cast conversion
operator Node() const;
explicit IntegerNode( const Node &n );
// Common generic Node functions
bool isRoot() const;
Node parent() const;
ustring pathName() const;
ustring elementName() const;
ImageFile destImageFile() const;
bool isAttached() const;
// Diagnostic functions:
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true, bool doUpcast = true );
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
IntegerNode( std::shared_ptr<IntegerNodeImpl> ni ); // internal use only
E57_OBJECT_IMPLEMENTATION( IntegerNode ) // Internal implementation details, not part of API, must be
// last in object
//! \endcond
};
class E57_DLL ScaledIntegerNode
{
public:
ScaledIntegerNode() = delete;
explicit ScaledIntegerNode( ImageFile destImageFile, int64_t rawValue, int64_t minimum, int64_t maximum,
double scale = 1.0, double offset = 0.0 );
explicit ScaledIntegerNode( ImageFile destImageFile, int rawValue, int64_t minimum, int64_t maximum,
double scale = 1.0, double offset = 0.0 );
explicit ScaledIntegerNode( ImageFile destImageFile, int rawValue, int minimum, int maximum, double scale = 1.0,
double offset = 0.0 );
explicit ScaledIntegerNode( ImageFile destImageFile, double scaledValue, double scaledMinimum,
double scaledMaximum, double scale = 1.0, double offset = 0.0 );
int64_t rawValue() const;
double scaledValue() const;
int64_t minimum() const;
double scaledMinimum() const;
int64_t maximum() const;
double scaledMaximum() const;
double scale() const;
double offset() const;
// Up/Down cast conversion
operator Node() const;
explicit ScaledIntegerNode( const Node &n );
// Common generic Node functions
bool isRoot() const;
Node parent() const;
ustring pathName() const;
ustring elementName() const;
ImageFile destImageFile() const;
bool isAttached() const;
// Diagnostic functions:
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true, bool doUpcast = true );
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
ScaledIntegerNode( std::shared_ptr<ScaledIntegerNodeImpl> ni ); // internal use only
E57_OBJECT_IMPLEMENTATION( ScaledIntegerNode ) // Internal implementation details, not part of
// API, must be last in object
//! \endcond
};
class E57_DLL FloatNode
{
public:
FloatNode() = delete;
explicit FloatNode( ImageFile destImageFile, double value = 0.0, FloatPrecision precision = E57_DOUBLE,
double minimum = E57_DOUBLE_MIN, double maximum = E57_DOUBLE_MAX );
double value() const;
FloatPrecision precision() const;
double minimum() const;
double maximum() const;
// Up/Down cast conversion
operator Node() const;
explicit FloatNode( const Node &n );
// Common generic Node functions
bool isRoot() const;
Node parent() const;
ustring pathName() const;
ustring elementName() const;
ImageFile destImageFile() const;
bool isAttached() const;
// Diagnostic functions:
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true, bool doUpcast = true );
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
FloatNode( std::shared_ptr<FloatNodeImpl> ni ); // internal use only
E57_OBJECT_IMPLEMENTATION( FloatNode ) // Internal implementation details, not part of API, must be
// last in object
//! \endcond
};
class E57_DLL StringNode
{
public:
StringNode() = delete;
explicit StringNode( ImageFile destImageFile, const ustring &value = "" );
ustring value() const;
// Up/Down cast conversion
operator Node() const;
explicit StringNode( const Node &n );
// Common generic Node functions
bool isRoot() const;
Node parent() const;
ustring pathName() const;
ustring elementName() const;
ImageFile destImageFile() const;
bool isAttached() const;
// Diagnostic functions:
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true, bool doUpcast = true );
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
friend class StringNodeImpl;
StringNode( std::shared_ptr<StringNodeImpl> ni ); // internal use only
E57_OBJECT_IMPLEMENTATION( StringNode ) // Internal implementation details, not part of API, must be
// last in object
//! \endcond
};
class E57_DLL BlobNode
{
public:
BlobNode() = delete;
explicit BlobNode( ImageFile destImageFile, int64_t byteCount );
int64_t byteCount() const;
void read( uint8_t *buf, int64_t start, size_t count );
void write( uint8_t *buf, int64_t start, size_t count );
// Up/Down cast conversion
operator Node() const;
explicit BlobNode( const Node &n );
// Common generic Node functions
bool isRoot() const;
Node parent() const;
ustring pathName() const;
ustring elementName() const;
ImageFile destImageFile() const;
bool isAttached() const;
// Diagnostic functions:
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true, bool doUpcast = true );
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
friend class E57XmlParser;
BlobNode( std::shared_ptr<BlobNodeImpl> ni ); // internal use only
// Internal use only, create blob already in a file
BlobNode( ImageFile destImageFile, int64_t fileOffset, int64_t length );
E57_OBJECT_IMPLEMENTATION( BlobNode ) // Internal implementation details, not
// part of API, must be last in object
//! \endcond
};
class E57_DLL ImageFile
{
public:
ImageFile() = delete;
ImageFile( const ustring &fname, const ustring &mode, ReadChecksumPolicy checksumPolicy = CHECKSUM_POLICY_ALL );
ImageFile( const char *input, const uint64_t size, ReadChecksumPolicy checksumPolicy = CHECKSUM_POLICY_ALL );
StructureNode root() const;
void close();
void cancel();
bool isOpen() const;
bool isWritable() const;
ustring fileName() const;
int writerCount() const;
int readerCount() const;
// Manipulate registered extensions in the file
void extensionsAdd( const ustring &prefix, const ustring &uri );
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;
// Field name functions:
bool isElementNameExtended( const ustring &elementName ) const;
void elementNameParse( const ustring &elementName, ustring &prefix, ustring &localPart ) const;
// Diagnostic functions:
void dump( int indent = 0, std::ostream &os = std::cout ) const;
void checkInvariant( bool doRecurse = true ) const;
bool operator==( ImageFile imf2 ) const;
bool operator!=( ImageFile imf2 ) const;
//! \cond documentNonPublic The following isn't part of the API, and isn't
//! documented.
private:
ImageFile( double ); // Give a second dummy constructor, better error msg
// for: ImageFile(0)
friend class Node;
friend class StructureNode;
friend class VectorNode;
friend class CompressedVectorNode;
friend class IntegerNode;
friend class ScaledIntegerNode;
friend class FloatNode;
friend class StringNode;
friend class BlobNode;
ImageFile( std::shared_ptr<ImageFileImpl> imfi ); // internal use only
E57_OBJECT_IMPLEMENTATION( ImageFile ) // Internal implementation details, not part of API, must be
// last in object
//! \endcond
};
}

View File

@@ -1,653 +0,0 @@
/*
* E57Simple - public header of E57 Simple API for reading/writing .e57 files.
*
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
* Copyright (c) 2020 PTC Inc.
*
* 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
//! @file E57SimpleData.h Data structures for E57 Simple API
#include "E57Format.h"
namespace e57
{
//! Indicates to use FloatNode instead of ScaledIntegerNode in fields that can use both.
constexpr double E57_NOT_SCALED_USE_FLOAT = 0.;
//! Indicates to use ScaledIntegerNode instead of FloatNode in fields that can use both.
constexpr double E57_NOT_SCALED_USE_INTEGER = -1.;
//! @cond documentNonPublic The following isn't part of the API, and isn't documented.
class ReaderImpl;
class WriterImpl;
//! @endcond
//! @brief Defines a rigid body translation in Cartesian coordinates.
struct E57_DLL Translation
{
double x{ 0. }; //!< The X coordinate of the translation (in meters)
double y{ 0. }; //!< The Y coordinate of the translation (in meters)
double z{ 0. }; //!< The Z coordinate of the translation (in meters)
bool operator==( const Translation &rhs ) const
{
return ( x == rhs.x ) && ( y == rhs.y ) && ( z == rhs.z );
}
bool operator!=( const Translation &rhs ) const
{
return !operator==( rhs );
}
static Translation identity()
{
return {};
}
};
//! @brief Represents a rigid body rotation.
struct E57_DLL Quaternion
{
double w{ 0. }; //!< The real part of the quaternion. Shall be nonnegative
double x{ 0. }; //!< The i coefficient of the quaternion
double y{ 0. }; //!< The j coefficient of the quaternion
double z{ 0. }; //!< The k coefficient of the quaternion
bool operator==( const Quaternion &rhs ) const
{
return ( w == rhs.w ) && ( x == rhs.x ) && ( y == rhs.y ) && ( z == rhs.z );
}
bool operator!=( const Quaternion &rhs ) const
{
return !operator==( rhs );
}
static Quaternion identity()
{
Quaternion identity;
identity.w = 1.;
return identity;
}
};
//! @brief Defines a rigid body transform in cartesian coordinates.
struct E57_DLL RigidBodyTransform
{
Quaternion rotation; //!< A unit quaternion representing the rotation, R, of the transform
Translation translation; //!< The translation point vector, t, of the transform
bool operator==( const RigidBodyTransform &rhs ) const
{
return ( rotation == rhs.rotation ) && ( translation == rhs.translation );
}
bool operator!=( const RigidBodyTransform &rhs ) const
{
return !operator==( rhs );
}
static RigidBodyTransform identity()
{
return { Quaternion::identity(), Translation::identity() };
}
};
//! @brief Specifies an axis-aligned box in local cartesian coordinates.
struct E57_DLL CartesianBounds
{
double xMinimum{ -E57_DOUBLE_MAX }; //!< The minimum extent of the bounding box in the X direction
double xMaximum{ E57_DOUBLE_MAX }; //!< The maximum extent of the bounding box in the X direction
double yMinimum{ -E57_DOUBLE_MAX }; //!< The minimum extent of the bounding box in the Y direction
double yMaximum{ E57_DOUBLE_MAX }; //!< The maximum extent of the bounding box in the Y direction
double zMinimum{ -E57_DOUBLE_MAX }; //!< The minimum extent of the bounding box in the Z direction
double zMaximum{ E57_DOUBLE_MAX }; //!< The maximum extent of the bounding box in the Z direction
bool operator==( const CartesianBounds &rhs ) const
{
return ( xMinimum == rhs.xMinimum ) && ( xMaximum == rhs.xMaximum ) && ( yMinimum == rhs.yMinimum ) &&
( yMaximum == rhs.yMaximum ) && ( zMinimum == rhs.zMinimum ) && ( zMaximum == rhs.zMaximum );
}
bool operator!=( const CartesianBounds &rhs ) const
{
return !operator==( rhs );
}
};
//! @brief Stores the bounds of some data in spherical coordinates.
struct E57_DLL SphericalBounds
{
SphericalBounds(); // constructor in the cpp to avoid exposing M_PI
double rangeMinimum; //!< The minimum extent of the bounding region in the r direction
double rangeMaximum; //!< The maximum extent of the bounding region in the r direction
double elevationMinimum; //!< The minimum extent of the bounding region from the horizontal plane
double elevationMaximum; //!< The maximum extent of the bounding region from the horizontal plane
double azimuthStart; //!< The starting azimuth angle defining the extent of the bounding region around the z axis
double azimuthEnd; //!< The ending azimuth angle defining the extent of the bounding region around the z axis
bool operator==( const SphericalBounds &rhs ) const
{
return ( rangeMinimum == rhs.rangeMinimum ) && ( rangeMaximum == rhs.rangeMaximum ) &&
( elevationMinimum == rhs.elevationMinimum ) && ( elevationMaximum == rhs.elevationMaximum ) &&
( azimuthStart == rhs.azimuthStart ) && ( azimuthEnd == rhs.azimuthEnd );
}
bool operator!=( const SphericalBounds &rhs ) const
{
return !operator==( rhs );
}
};
//! @brief Stores the minimum and maximum of rowIndex, columnIndex, and returnIndex fields for a set of points.
struct E57_DLL IndexBounds
{
int64_t rowMinimum{ 0 }; //!< The minimum rowIndex value of any point represented by this IndexBounds object.
int64_t rowMaximum{ 0 }; //!< The maximum rowIndex value of any point represented by this IndexBounds object.
int64_t columnMinimum{
0
}; //!< The minimum columnIndex value of any point represented by this IndexBounds object.
int64_t columnMaximum{
0
}; //!< The maximum columnIndex value of any point represented by this IndexBounds object.
int64_t returnMinimum{
0
}; //!< The minimum returnIndex value of any point represented by this IndexBounds object.
int64_t returnMaximum{
0
}; //!< The maximum returnIndex value of any point represented by this IndexBounds object.
bool operator==( const IndexBounds &rhs ) const
{
return ( rowMinimum == rhs.rowMinimum ) && ( rowMaximum == rhs.rowMaximum ) &&
( columnMinimum == rhs.columnMinimum ) && ( columnMaximum == rhs.columnMaximum ) &&
( returnMinimum == rhs.returnMinimum ) && ( returnMaximum == rhs.returnMaximum );
}
bool operator!=( const IndexBounds &rhs ) const
{
return !operator==( rhs );
}
};
//! @brief Specifies the limits for the value of signal intensity that a sensor is capable of producing
struct E57_DLL IntensityLimits
{
double intensityMinimum{ 0. }; //!< The minimum producible intensity value. Unit is unspecified.
double intensityMaximum{ 0. }; //!< The maximum producible intensity value. Unit is unspecified.
bool operator==( const IntensityLimits &rhs ) const
{
return ( intensityMinimum == rhs.intensityMinimum ) && ( intensityMaximum == rhs.intensityMaximum );
}
bool operator!=( const IntensityLimits &rhs ) const
{
return !operator==( rhs );
}
};
//! @brief Specifies the limits for the value of red, green, and blue color that a sensor is capable of producing.
struct E57_DLL ColorLimits
{
double colorRedMinimum{ 0. }; //!< The minimum producible red color value. Unit is unspecified.
double colorRedMaximum{ 0. }; //!< The maximum producible red color value. Unit is unspecified.
double colorGreenMinimum{ 0. }; //!< The minimum producible green color value. Unit is unspecified.
double colorGreenMaximum{ 0. }; //!< The maximum producible green color value. Unit is unspecified.
double colorBlueMinimum{ 0. }; //!< The minimum producible blue color value. Unit is unspecified.
double colorBlueMaximum{ 0. }; //!< The maximum producible blue color value. Unit is unspecified.
bool operator==( const ColorLimits &rhs ) const
{
return ( colorRedMinimum == rhs.colorRedMinimum ) && ( colorRedMaximum == rhs.colorRedMaximum ) &&
( colorGreenMinimum == rhs.colorGreenMinimum ) && ( colorGreenMaximum == rhs.colorGreenMaximum ) &&
( colorBlueMinimum == rhs.colorBlueMinimum ) && ( colorBlueMaximum == rhs.colorBlueMaximum );
}
bool operator!=( const ColorLimits &rhs ) const
{
return !operator==( rhs );
}
};
//! @brief Encodes date and time.
//! @details The date and time is encoded using a single floating point number, stored as an E57 Float element which
//! is based on the Global Positioning
//! System (GPS) time scale.
struct E57_DLL DateTime
{
double dateTimeValue{
0.
}; //!< The time, in seconds, since GPS time was zero. This time specification may include fractions of a second.
int32_t isAtomicClockReferenced{
0
}; //!< This element should be present, and its value set to 1 if, and only if, the time stored in the
//!< dateTimeValue element is obtained from an atomic clock time source. Shall be either 0 or 1.
bool operator==( const DateTime &rhs ) const
{
return ( dateTimeValue == rhs.dateTimeValue ) && ( isAtomicClockReferenced == rhs.isAtomicClockReferenced );
}
bool operator!=( const DateTime &rhs ) const
{
return !operator==( rhs );
}
};
//! @brief Stores the top-level information for the XML section of the file.
struct E57_DLL E57Root
{
ustring formatName; //!< Contains the string "ASTM E57 3D Image File"
ustring guid; //!< A globally unique identification string for the current version of the file
uint32_t versionMajor{ 1 }; //!< Major version number, should be 1
uint32_t versionMinor{ 0 }; //!< Minor version number, should be 0
ustring e57LibraryVersion; //!< The version identifier for the E57 file format library that wrote the file.
DateTime creationDateTime; //!< Date/time that the file was created
int64_t data3DSize{ 0 }; //!< Size of the Data3D vector for storing 3D imaging data
int64_t images2DSize{ 0 }; //!< Size of the A heterogeneous Vector of Images2D Structures for storing 2D images
//!< from a camera or similar device.
ustring coordinateMetadata; //!< Information describing the Coordinate Reference System to be used for the file
};
//! @brief Stores information about a single group of points in a row or column
struct E57_DLL LineGroupRecord
{
int64_t idElementValue{
0
}; //!< The value of the identifying element of all members in this group. Shall be in the interval [0, 2^63).
int64_t startPointIndex{
0
}; //!< The record number of the first point in the continuous interval. Shall be in the interval [0, 2^63).
int64_t pointCount{
0
}; //!< The number of PointRecords in the group. Shall be in the interval [1, 2^63). May be zero.
CartesianBounds cartesianBounds; //!< The bounding box (in Cartesian coordinates) of all points in the group
//!< (in the local coordinate system of the points).
SphericalBounds sphericalBounds; //!< The bounding region (in spherical coordinates) of all the points in the
//!< group (in the local coordinate system of the points).
};
//! @brief Stores a set of point groups organized by the rowIndex or columnIndex attribute of the PointRecord
struct E57_DLL GroupingByLine
{
ustring idElementName; //!< The name of the PointRecord element that identifies which group the point is in. The
//!< value of this string must be "rowIndex" or "columnIndex"
int64_t groupsSize{ 0 }; //!< Size of the groups compressedVector of LineGroupRecord structures
int64_t pointCountSize{ 0 }; //!< This is the size value for the LineGroupRecord::pointCount.
};
//! @brief Supports the division of points within an Data3D into logical groupings
struct E57_DLL PointGroupingSchemes
{
GroupingByLine groupingByLine; //!< Grouping information by row or column index
};
//! @brief Used to interrogate if standardized fields are available
struct E57_DLL PointStandardizedFieldsAvailable
{
bool cartesianXField{ false }; //!< Indicates that the PointRecord cartesianX field is active
bool cartesianYField{ false }; //!< Indicates that the PointRecord cartesianY field is active
bool cartesianZField{ false }; //!< Indicates that the PointRecord cartesianZ field is active
bool cartesianInvalidStateField{
false
}; //!< Indicates that the PointRecord cartesianInvalidState field is active
bool sphericalRangeField{ false }; //!< Indicates that the PointRecord sphericalRange field is active
bool sphericalAzimuthField{ false }; //!< Indicates that the PointRecord sphericalAzimuth field is active
bool sphericalElevationField{ false }; //!< Indicates that the PointRecord sphericalElevation field is active
bool sphericalInvalidStateField{
false
}; //!< Indicates that the PointRecord sphericalInvalidState field is active
double pointRangeMinimum{
E57_FLOAT_MIN
}; //!< Indicates that the PointRecord cartesian and range fields should be configured with this minimum value
//!< -E57_FLOAT_MAX or -E57_DOUBLE_MAX. If using a ScaledIntegerNode then this needs to be a minimum range
//!< value.
double pointRangeMaximum{
E57_FLOAT_MAX
}; //!< Indicates that the PointRecord cartesian and range fields should be configured with this maximum value
//!< E57_FLOAT_MAX or E57_DOUBLE_MAX. If using a ScaledIntegerNode then this needs to be a maximum range value.
double pointRangeScaledInteger{
E57_NOT_SCALED_USE_FLOAT
}; //!< Indicates that the PointRecord cartesain and range fields should be configured as a ScaledIntegerNode with
//!< this scale setting. If 0. then use FloatNode.
double angleMinimum{
E57_FLOAT_MIN
}; //!< Indicates that the PointRecord angle fields should be configured with this minimum value -E57_FLOAT_MAX or
//!< -E57_DOUBLE_MAX. If using a ScaledIntegerNode then this needs to be a minimum angle value.
double angleMaximum{
E57_FLOAT_MAX
}; //!< Indicates that the PointRecord angle fields should be configured with this maximum value E57_FLOAT_MAX or
//!< E57_DOUBLE_MAX. If using a ScaledIntegerNode then this needs to be a maximum angle value.
double angleScaledInteger{
E57_NOT_SCALED_USE_FLOAT
}; //!< Indicates that the PointRecord angle fields should be configured as a ScaledIntegerNode with this scale
//!< setting. If 0. then use FloatNode.
bool rowIndexField{ false }; //!< Indicates that the PointRecord rowIndex field is active
uint32_t rowIndexMaximum{ E57_UINT32_MAX }; //!< Indicates that the PointRecord index fields should be configured
//!< with this maximum value where the minimum will be set to 0.
bool columnIndexField{ false }; //!< Indicates that the PointRecord columnIndex field is active
uint32_t columnIndexMaximum{
E57_UINT32_MAX
}; //!< Indicates that the PointRecord index fields should be configured with this maximum value where the minimum
//!< will be set to 0.
bool returnIndexField{ false }; //!< Indicates that the PointRecord returnIndex field is active
bool returnCountField{ false }; //!< Indicates that the PointRecord returnCount field is active
uint8_t returnMaximum{ E57_UINT8_MAX }; //!< Indicates that the PointRecord return fields should be configured
//!< with this maximum value where the minimum will be set to 0.
bool timeStampField{ false }; //!< Indicates that the PointRecord timeStamp field is active
bool isTimeStampInvalidField{ false }; //!< Indicates that the PointRecord isTimeStampInvalid field is active
double timeMaximum{
E57_DOUBLE_MAX
}; //!< Indicates that the PointRecord timeStamp fields should be configured with this maximum value. like
//!< E57_UINT32_MAX, E57_FLOAT_MAX or E57_DOUBLE_MAX
double timeMinimum{ E57_DOUBLE_MIN }; //!< Indicates that the PointRecord timeStamp fields should be configured
//!< with this minimum value -E57_FLOAT_MAX or -E57_DOUBLE_MAX. If using a
//!< ScaledIntegerNode then this needs to be a minimum time value.
double timeScaledInteger{
E57_NOT_SCALED_USE_FLOAT
}; //!< Indicates that the PointRecord timeStamp fields should be configured as a ScaledIntegerNode with this
//!< scale setting. If 0. then use FloatNode, if -1. use IntegerNode.
bool intensityField{ false }; //!< Indicates that the PointRecord intensity field is active
bool isIntensityInvalidField{ false }; //!< Indicates that the PointRecord isIntensityInvalid field is active
double intensityScaledInteger{
E57_NOT_SCALED_USE_INTEGER
}; //!< Indicates that the PointRecord intensity fields should be configured as a ScaledIntegerNode with this
//!< setting. If 0. then use FloatNode, if -1. use IntegerNode
bool colorRedField{ false }; //!< indicates that the PointRecord colorRed field is active
bool colorGreenField{ false }; //!< indicates that the PointRecord colorGreen field is active
bool colorBlueField{ false }; //!< indicates that the PointRecord colorBlue field is active
bool isColorInvalidField{ false }; //!< Indicates that the PointRecord isColorInvalid field is active
bool normalX{ false }; //!< Indicates that the PointRecord nor:normalX field is active
bool normalY{ false }; //!< Indicates that the PointRecord nor:normalY field is active
bool normalZ{ false }; //!< Indicates that the PointRecord nor:normalZ field is active
};
//! @brief Stores the top-level information for a single lidar scan
struct E57_DLL Data3D
{
ustring name; //!< A user-defined name for the Data3D.
ustring guid; //!< A globally unique identification string for the current version of the Data3D object
std::vector<ustring> originalGuids; //!< A vector of globally unique identification Strings from which the points
//!< in this Data3D originated.
ustring description; //!< A user-defined description of the Image
ustring sensorVendor; //!< The name of the manufacturer for the sensor used to collect the points in this Data3D.
ustring sensorModel; //!< The model name or number for the sensor.
ustring sensorSerialNumber; //!< The serial number for the sensor.
ustring sensorHardwareVersion; //!< The version number for the sensor hardware at the time of data collection.
ustring sensorSoftwareVersion; //!< The version number for the software used for the data collection.
ustring sensorFirmwareVersion; //!< The version number for the firmware installed in the sensor at the time of
//!< data collection.
float temperature{ E57_FLOAT_MAX }; //!< The ambient temperature, measured at the sensor, at the time of data
//!< collection (in degrees Celsius).
float relativeHumidity{ E57_FLOAT_MAX }; //!< The percentage relative humidity, measured at the sensor, at the
//!< time of data collection. Shall be in the interval [0, 100].
float atmosphericPressure{ E57_FLOAT_MAX }; //!< The atmospheric pressure, measured at the sensor, at the time of
//!< data collection (in Pascals). Shall be positive.
DateTime acquisitionStart; //!< The start date and time that the data was acquired.
DateTime acquisitionEnd; //!< The end date and time that the data was acquired.
RigidBodyTransform pose; //!< A rigid body transform that describes the coordinate frame of the 3D imaging
//!< system origin in the file-level coordinate system.
IndexBounds indexBounds; //!< The bounds of the row, column, and return number of all the points in this Data3D.
CartesianBounds cartesianBounds; //!< The bounding region (in cartesian coordinates) of all the points in
//!< this Data3D (in the local coordinate system of the points).
SphericalBounds sphericalBounds; //!< The bounding region (in spherical coordinates) of all the points in
//!< this Data3D (in the local coordinate system of the points).
IntensityLimits
intensityLimits; //!< The limits for the value of signal intensity that the sensor is capable of producing.
ColorLimits colorLimits; //!< The limits for the value of red, green, and blue color that the sensor is
//!< capable of producing.
PointGroupingSchemes pointGroupingSchemes; //!< The defined schemes that group points in different ways
PointStandardizedFieldsAvailable
pointFields; //!< This defines the active fields used in the WritePoints function.
int64_t pointsSize{ 0 }; //!< Total size of the compressed vector of PointRecord structures referring to the
//!< binary data that actually stores the point data
};
//! @brief Stores pointers to user-provided buffers
template <typename COORDTYPE = float> struct Data3DPointsData_t
{
COORDTYPE *cartesianX{
nullptr
}; //!< pointer to a buffer with the X coordinate (in meters) of the point in Cartesian coordinates
COORDTYPE *cartesianY{
nullptr
}; //!< pointer to a buffer with the Y coordinate (in meters) of the point in Cartesian coordinates
COORDTYPE *cartesianZ{
nullptr
}; //!< pointer to a buffer with the Z coordinate (in meters) of the point in Cartesian coordinates
int8_t *cartesianInvalidState{ nullptr }; //!< Value = 0 if the point is considered valid, 1 otherwise
float *intensity{ nullptr }; //!< pointer to a buffer with the Point response intensity. Unit is unspecified
int8_t *isIntensityInvalid{ nullptr }; //!< Value = 0 if the intensity is considered valid, 1 otherwise
uint8_t *colorRed{ nullptr }; //!< pointer to a buffer with the Red color coefficient. Unit is unspecified
uint8_t *colorGreen{ nullptr }; //!< pointer to a buffer with the Green color coefficient. Unit is unspecified
uint8_t *colorBlue{ nullptr }; //!< pointer to a buffer with the Blue color coefficient. Unit is unspecified
int8_t *isColorInvalid{ nullptr }; //!< Value = 0 if the color is considered valid, 1 otherwise
COORDTYPE *sphericalRange{
nullptr
}; //!< pointer to a buffer with the range (in meters) of points in spherical coordinates. Shall be non-negative
COORDTYPE *sphericalAzimuth{
nullptr
}; //!< pointer to a buffer with the Azimuth angle (in radians) of point in spherical coordinates
COORDTYPE *sphericalElevation{
nullptr
}; //!< pointer to a buffer with the Elevation angle (in radians) of point in spherical coordinates
int8_t *sphericalInvalidState{ nullptr }; //!< Value = 0 if the range is considered valid, 1 otherwise
int32_t *rowIndex{ nullptr }; //!< pointer to a buffer with the row number of point (zero based). This is useful
//!< for data that is stored in a regular grid. Shall be in the interval (0, 2^31).
int32_t *columnIndex{
nullptr
}; //!< pointer to a buffer with the column number of point (zero based). This is useful for data that is stored
//!< in a regular grid. Shall be in the interval (0, 2^31).
int8_t *returnIndex{
nullptr
}; //!< pointer to a buffer with the number of this return (zero based). That is, 0 is the first return, 1 is the
//!< second, and so on. Shall be in the interval (0, returnCount). Only for multi-return sensors.
int8_t *returnCount{
nullptr
}; //!< pointer to a buffer with the total number of returns for the pulse that this corresponds to. Shall be in
//!< the interval (0, 2^7). Only for multi-return sensors.
double *timeStamp{
nullptr
}; //!< pointer to a buffer with the time (in seconds) since the start time for the data, which is given by
//!< acquisitionStart in the parent Data3D Structure. Shall be non-negative
int8_t *isTimeStampInvalid{ nullptr }; //!< Value = 0 if the timeStamp is considered valid, 1 otherwise
// E57_EXT_surface_normals
float *normalX{ nullptr }; //!< The X component of a surface normal vector (E57_EXT_surface_normals).
float *normalY{ nullptr }; //!< The Y component of a surface normal vector (E57_EXT_surface_normals).
float *normalZ{ nullptr }; //!< The Z component of a surface normal vector (E57_EXT_surface_normals).
};
typedef Data3DPointsData_t<float> Data3DPointsData;
typedef Data3DPointsData_t<double> Data3DPointsData_d;
//! @brief Stores an image that is to be used only as a visual reference.
struct E57_DLL VisualReferenceRepresentation
{
int64_t jpegImageSize{ 0 }; //!< Size of JPEG format image data in BlobNode.
int64_t pngImageSize{ 0 }; //!< Size of PNG format image data in BlobNode.
int64_t imageMaskSize{ 0 }; //!< Size of PNG format image mask in BlobNode.
int32_t imageWidth{ 0 }; //!< The image width (in pixels). Shall be positive
int32_t imageHeight{ 0 }; //!< The image height (in pixels). Shall be positive
bool operator==( const VisualReferenceRepresentation &rhs ) const
{
return ( jpegImageSize == rhs.jpegImageSize ) && ( pngImageSize == rhs.pngImageSize ) &&
( imageMaskSize == rhs.imageMaskSize ) && ( imageWidth == rhs.imageWidth ) &&
( imageHeight == rhs.imageHeight );
}
bool operator!=( const VisualReferenceRepresentation &rhs ) const
{
return !operator==( rhs );
}
};
//! @brief Stores an image that is mapped from 3D using the pinhole camera projection model.
struct E57_DLL PinholeRepresentation
{
int64_t jpegImageSize{ 0 }; //!< Size of JPEG format image data in BlobNode.
int64_t pngImageSize{ 0 }; //!< Size of PNG format image data in BlobNode.
int64_t imageMaskSize{ 0 }; //!< Size of PNG format image mask in BlobNode.
int32_t imageWidth{ 0 }; //!< The image width (in pixels). Shall be positive
int32_t imageHeight{ 0 }; //!< The image height (in pixels). Shall be positive
double focalLength{ 0. }; //!< The camera's focal length (in meters). Shall be positive
double pixelWidth{ 0. }; //!< The width of the pixels in the camera (in meters). Shall be positive
double pixelHeight{ 0. }; //!< The height of the pixels in the camera (in meters). Shall be positive
double principalPointX{
0.
}; //!< The X coordinate in the image of the principal point, (in pixels). The principal point is the intersection
//!< of the z axis of the camera coordinate frame with the image plane.
double principalPointY{ 0. }; //!< The Y coordinate in the image of the principal point (in pixels).
bool operator==( const PinholeRepresentation &rhs ) const
{
return ( jpegImageSize == rhs.jpegImageSize ) && ( pngImageSize == rhs.pngImageSize ) &&
( imageMaskSize == rhs.imageMaskSize ) && ( imageWidth == rhs.imageWidth ) &&
( imageHeight == rhs.imageHeight ) && ( focalLength == rhs.focalLength ) &&
( pixelWidth == rhs.pixelWidth ) && ( pixelHeight == rhs.pixelHeight ) &&
( principalPointX == rhs.principalPointX ) && ( principalPointY == rhs.principalPointY );
}
bool operator!=( const PinholeRepresentation &rhs ) const
{
return !operator==( rhs );
}
};
//! @brief Stores an image that is mapped from 3D using a spherical projection model
struct E57_DLL SphericalRepresentation
{
int64_t jpegImageSize{ 0 }; //!< Size of JPEG format image data in BlobNode.
int64_t pngImageSize{ 0 }; //!< Size of PNG format image data in BlobNode.
int64_t imageMaskSize{ 0 }; //!< Size of PNG format image mask in BlobNode.
int32_t imageWidth{ 0 }; //!< The image width (in pixels). Shall be positive
int32_t imageHeight{ 0 }; //!< The image height (in pixels). Shall be positive
double pixelWidth{ 0. }; //!< The width of a pixel in the image (in radians). Shall be positive
double pixelHeight{ 0. }; //!< The height of a pixel in the image (in radians). Shall be positive.
bool operator==( const SphericalRepresentation &rhs ) const
{
return ( jpegImageSize == rhs.jpegImageSize ) && ( pngImageSize == rhs.pngImageSize ) &&
( imageMaskSize == rhs.imageMaskSize ) && ( imageWidth == rhs.imageWidth ) &&
( imageHeight == rhs.imageHeight ) && ( pixelWidth == rhs.pixelWidth ) &&
( pixelHeight == rhs.pixelHeight );
}
bool operator!=( const SphericalRepresentation &rhs ) const
{
return !operator==( rhs );
}
};
//! @brief Stores an image that is mapped from 3D using a cylindrical projection model.
struct E57_DLL CylindricalRepresentation
{
int64_t jpegImageSize{ 0 }; //!< Size of JPEG format image data in Blob.
int64_t pngImageSize{ 0 }; //!< Size of PNG format image data in Blob.
int64_t imageMaskSize{ 0 }; //!< Size of PNG format image mask in Blob.
int32_t imageWidth{ 0 }; //!< The image width (in pixels). Shall be positive
int32_t imageHeight{ 0 }; //!< The image height (in pixels). Shall be positive
double pixelWidth{ 0. }; //!< The width of a pixel in the image (in radians). Shall be positive
double pixelHeight{ 0. }; //!< The height of a pixel in the image (in meters). Shall be positive
double radius{ 0. }; //!< The closest distance from the cylindrical image surface to the center of projection
//!< (that is, the radius of the cylinder) (in meters). Shall be non-negative
double principalPointY{ 0. }; //!< The Y coordinate in the image of the principal point (in pixels). This is the
//!< intersection of the z = 0 plane with the image
bool operator==( const CylindricalRepresentation &rhs ) const
{
return ( jpegImageSize == rhs.jpegImageSize ) && ( pngImageSize == rhs.pngImageSize ) &&
( imageMaskSize == rhs.imageMaskSize ) && ( imageWidth == rhs.imageWidth ) &&
( imageHeight == rhs.imageHeight ) && ( pixelWidth == rhs.pixelWidth ) &&
( pixelHeight == rhs.pixelHeight ) && ( radius == rhs.radius ) &&
( principalPointY == rhs.principalPointY );
}
bool operator!=( const CylindricalRepresentation &rhs ) const
{
return !operator==( rhs );
}
};
//! @brief Stores an image from a camera
struct E57_DLL Image2D
{
ustring name; //!< A user-defined name for the Image2D.
ustring guid; //!< A globally unique identification string for the current version of the Image2D object
ustring description; //!< A user-defined description of the Image2D
DateTime acquisitionDateTime; //!< The date and time that the image was taken
ustring associatedData3DGuid; //!< The globally unique identification string (guid element) for the Data3D that
//!< was being acquired when the picture was taken
ustring sensorVendor; //!< The name of the manufacturer for the sensor used to collect the points in this Data3D.
ustring sensorModel; //!< The model name or number for the sensor.
ustring sensorSerialNumber; //!< The serial number for the sensor.
RigidBodyTransform pose; //!< A rigid body transform that describes the coordinate frame of the camera in the
//!< file-level coordinate system
VisualReferenceRepresentation
visualReferenceRepresentation; //!< Representation for an image that does not define any camera projection
//!< model. The image is to be used for visual reference only
PinholeRepresentation
pinholeRepresentation; //!< Representation for an image using the pinhole camera projection model
SphericalRepresentation
sphericalRepresentation; //!< Representation for an image using the spherical camera projection model.
CylindricalRepresentation
cylindricalRepresentation; //!< Representation for an image using the cylindrical camera projection model
};
//! @brief Identifies the format representation for the image data
enum Image2DType
{
E57_NO_IMAGE = 0, //!< No image data
E57_JPEG_IMAGE = 1, //!< JPEG format image data.
E57_PNG_IMAGE = 2, //!< PNG format image data.
E57_PNG_IMAGE_MASK = 3 //!< PNG format image mask.
};
//! @brief Identifies the representation for the image data
enum Image2DProjection
{
E57_NO_PROJECTION = 0, //!< No representation for the image data is present
E57_VISUAL = 1, //!< VisualReferenceRepresentation for the image data
E57_PINHOLE = 2, //!< PinholeRepresentation for the image data
E57_SPHERICAL = 3, //!< SphericalRepresentation for the image data
E57_CYLINDRICAL = 4 //!< CylindricalRepresentation for the image data
};
} // end namespace e57

View File

@@ -1,186 +0,0 @@
/*
* E57Simple - public header of E57 Simple API for reading/writing .e57 files.
*
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
* Copyright (c) 2020 PTC Inc.
*
* 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
//! @file E57SimpleReader.h E57 Simple API for reading E57
#include "E57SimpleData.h"
namespace e57
{
//! @brief Used for reading of the E57 file with E57 Simple API
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
bool IsOpen() const;
//! @brief This function closes the file
bool Close();
//! @name File information
//!@{
//! @brief This function 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
//!@{
//! @brief This function 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
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,
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;
//!@}
//! @name Data3D
//!@{
//! @brief This function 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
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 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,
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
CompressedVectorReader SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
const Data3DPointsData &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
CompressedVectorReader SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
const Data3DPointsData_d &buffers ) const;
//!@}
//! @name Foundation API file information
//!@{
//! @brief Returns the file raw E57Root Structure Node
StructureNode GetRawE57Root() const;
//! @brief Returns the raw Data3D Vector Node
VectorNode GetRawData3D() const;
//! @brief Returns the raw Image2D Vector Node
VectorNode GetRawImages2D() const;
//! @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.
protected:
friend class ReaderImpl;
E57_OBJECT_IMPLEMENTATION( Reader ) // Internal implementation details, not part of API, must be last in object
//! @endcond
}; // end Reader class
} // end namespace e57

View File

@@ -1,137 +0,0 @@
/*
* E57Simple - public header of E57 Simple API for reading/writing .e57 files.
*
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
* Copyright (c) 2020 PTC Inc.
*
* 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
//! @file E57SimpleWriter.h E57 Simple API for writing E57
#include "E57SimpleData.h"
namespace e57
{
//! @brief Used for writing of the E57 file with E57 Simple API
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 This function returns true if the file is open
bool IsOpen() const;
//! @brief This function closes the file
bool Close();
//! @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
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 );
//!@}
//! @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.
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
CompressedVectorWriter SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
const Data3DPointsData &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
CompressedVectorWriter SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
const Data3DPointsData_d &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,
int64_t *startPointIndex, int64_t *pointCount );
//!@}
//! @name Foundation API file information
//!@{
//! @brief This function returns the file raw E57Root Structure Node
StructureNode GetRawE57Root();
//! @brief This function returns the raw Data3D Vector Node
VectorNode GetRawData3D();
//! @brief This function returns the raw Image2D Vector Node
VectorNode GetRawImages2D();
//! @brief This function 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.
protected:
friend class WriterImpl;
E57_OBJECT_IMPLEMENTATION( Writer ) // Internal implementation details, not part of API, must be last in object
//! @endcond
}; // end Writer class
} // end namespace e57

View File

@@ -1,226 +0,0 @@
/*
* 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.
*/
#include "BlobNodeImpl.h"
#include "CheckedFile.h"
#include "ImageFileImpl.h"
#include "SectionHeaders.h"
namespace e57
{
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
blobLogicalLength_ = byteCount;
/// Round segment length up to multiple of 4 bytes
binarySectionLogicalLength_ = sizeof( BlobSectionHeader ) + blobLogicalLength_;
unsigned remainder = binarySectionLogicalLength_ % 4;
if ( remainder > 0 )
{
binarySectionLogicalLength_ += 4 - remainder;
}
/// 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
BlobSectionHeader header;
header.sectionLogicalLength = binarySectionLogicalLength_;
#ifdef E57_MAX_VERBOSE
header.dump(); //???
#endif
/// 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 )
{
/// 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
blobLogicalLength_ = length;
binarySectionLogicalStart_ = imf->file_->physicalToLogical( fileOffset );
binarySectionLogicalLength_ = sizeof( BlobSectionHeader ) + blobLogicalLength_;
}
bool BlobNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
{
// don't checkImageFileOpen, NodeImpl() will do it
/// Same node type?
if ( ni->type() != E57_BLOB )
{
return ( false );
}
/// Downcast to shared_ptr<BlobNodeImpl>
std::shared_ptr<BlobNodeImpl> bi( std::static_pointer_cast<BlobNodeImpl>( ni ) );
/// blob lengths must match
if ( blobLogicalLength_ != bi->blobLogicalLength_ )
{
return ( false );
}
/// ignore blob contents, doesn't have to match
/// Types match
return ( true );
}
bool BlobNodeImpl::isDefined( const ustring &pathName )
{
// don't checkImageFileOpen, NodeImpl() will do it
/// We have no sub-structure, so if path not empty return false
return pathName.empty();
}
int64_t BlobNodeImpl::byteCount()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( blobLogicalLength_ );
}
void BlobNodeImpl::read( uint8_t *buf, int64_t start, size_t count )
{
//??? check start not negative
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_ ) );
}
ImageFileImplSharedPtr imf( destImageFile_ );
imf->file_->seek( binarySectionLogicalStart_ + sizeof( BlobSectionHeader ) + start );
imf->file_->read( reinterpret_cast<char *>( buf ),
static_cast<size_t>( count ) ); //??? arg1 void* ?
}
void BlobNodeImpl::write( uint8_t *buf, int64_t start, size_t count )
{
//??? check start not negative
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
ImageFileImplSharedPtr destImageFile( destImageFile_ );
if ( !destImageFile->isWriter() )
{
throw E57_EXCEPTION2( E57_ERROR_FILE_IS_READ_ONLY, "fileName=" + destImageFile->fileName() );
}
if ( !isAttached() )
{
throw E57_EXCEPTION2( E57_ERROR_NODE_UNATTACHED, "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_ ) );
}
ImageFileImplSharedPtr imf( destImageFile_ );
imf->file_->seek( binarySectionLogicalStart_ + sizeof( BlobSectionHeader ) + start );
imf->file_->write( reinterpret_cast<char *>( buf ),
static_cast<size_t>( count ) ); //??? arg1 void* ?
}
void BlobNodeImpl::checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin )
{
// 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?
if ( pathNames.find( relativePathName( origin ) ) == pathNames.end() )
{
throw E57_EXCEPTION2( E57_ERROR_NO_BUFFER_FOR_ELEMENT, "this->pathName=" + this->pathName() );
}
}
void BlobNodeImpl::writeXml( ImageFileImplSharedPtr /*imf*/, CheckedFile &cf, int indent,
const char *forcedFieldName )
{
// don't checkImageFileOpen
ustring fieldName;
if ( forcedFieldName )
{
fieldName = forcedFieldName;
}
else
{
fieldName = elementName_;
}
//??? need to implement
//??? 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";
}
#ifdef E57_DEBUG
void BlobNodeImpl::dump( int indent, std::ostream &os ) const
{
// don't checkImageFileOpen
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;
// size_t i;
// for (i = 0; i < blobLogicalLength_ && i < 10; i++) {
// uint8_t b;
// read(&b, i, 1);
// os << space(indent) << "data[" << i << "]: "<< static_cast<int>(b)
// << std::endl;
// }
// if (i < blobLogicalLength_)
// os << space(indent) << "more data unprinted..." << std::endl;
}
#endif
}

View File

@@ -1,65 +0,0 @@
#pragma once
/*
* 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.
*/
#include "NodeImpl.h"
namespace e57
{
class BlobNodeImpl : public NodeImpl
{
public:
BlobNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t byteCount );
BlobNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t fileOffset, int64_t length );
~BlobNodeImpl() override = default;
NodeType type() const override
{
return E57_BLOB;
}
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
bool isDefined( const ustring &pathName ) override;
int64_t byteCount();
void read( uint8_t *buf, int64_t start, size_t count );
void write( uint8_t *buf, int64_t start, size_t count );
void checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin ) override;
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
const char *forcedFieldName = nullptr ) override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
private:
uint64_t blobLogicalLength_;
uint64_t binarySectionLogicalStart_;
uint64_t binarySectionLogicalLength_;
};
}

View File

@@ -1,63 +0,0 @@
# SPDX-License-Identifier: MIT
# 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
)
target_include_directories( E57Format
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)

View File

@@ -1,803 +0,0 @@
/*
* 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.
*/
// convenience for all the BSDs
#if defined( __FreeBSD__) || defined( __NetBSD__) || defined( __OpenBSD__)
#define __BSD
#endif
#if defined( _WIN32 )
#if defined( _MSC_VER )
#include <codecvt>
#include <io.h>
#elif defined( __GNUC__ )
#define _LARGEFILE64_SOURCE
#define __LARGE64_FILES
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#else
#error "no supported compiler defined"
#endif
#elif defined( __linux__ )
#define _LARGEFILE64_SOURCE
#define __LARGE64_FILES
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#elif defined(__BSD)
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#elif defined( __APPLE__ )
#include <sys/types.h>
#include <unistd.h>
#else
#error "no supported OS platform defined"
#endif
#include <cmath>
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include "CRC.h"
#include "CheckedFile.h"
//#define E57_CHECK_FILE_DEBUG
#ifdef E57_CHECK_FILE_DEBUG
#include <cassert>
#endif
#ifndef O_BINARY
constexpr int O_BINARY = 0;
#endif
using namespace e57;
// These extra definitions are required in C++11.
// In C++17, "static constexpr" is implicitly inline, so these are not required.
constexpr size_t CheckedFile::physicalPageSizeLog2;
constexpr size_t CheckedFile::physicalPageSize;
constexpr uint64_t CheckedFile::physicalPageSizeMask;
constexpr size_t CheckedFile::logicalPageSize;
/// Tool class to read buffer efficiently without
/// multiplying copy operations.
///
/// WARNING: pointer input is handled by user!
class e57::BufferView
{
public:
/// @param[IN] input: filled buffer owned by caller.
/// @param[IN] size: size of input
BufferView( const char *input, uint64_t size ) : streamSize_( size ), stream_( input )
{
}
uint64_t pos() const
{
return cursorStream_;
}
bool seek( uint64_t offset, int whence )
{
if ( whence == SEEK_CUR )
{
cursorStream_ += offset;
}
else if ( whence == SEEK_SET )
{
cursorStream_ = offset;
}
else if ( whence == SEEK_END )
{
cursorStream_ = streamSize_ - offset;
}
if ( cursorStream_ > streamSize_ )
{
cursorStream_ = streamSize_;
return false;
}
return true;
}
void read( char *buffer, uint64_t count )
{
const uint64_t start = cursorStream_;
for ( uint64_t i = 0; i < count; ++i )
{
buffer[i] = stream_[start + i];
++cursorStream_;
}
}
private:
const uint64_t streamSize_;
uint64_t cursorStream_ = 0;
const char *stream_;
};
CheckedFile::CheckedFile( const ustring &fileName, Mode mode, ReadChecksumPolicy policy ) :
fileName_( fileName ), checkSumPolicy_( policy )
{
switch ( mode )
{
case ReadOnly:
fd_ = open64( fileName_, O_RDONLY | O_BINARY, 0 );
readOnly_ = true;
physicalLength_ = lseek64( 0LL, SEEK_END );
lseek64( 0, SEEK_SET );
logicalLength_ = physicalToLogical( physicalLength_ );
break;
case WriteCreate:
/// File truncated to zero length if already exists
fd_ = open64( fileName_, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IWRITE | S_IREAD );
break;
case WriteExisting:
fd_ = open64( fileName_, O_RDWR | O_BINARY, 0 );
logicalLength_ = physicalToLogical( length( Physical ) ); //???
break;
}
}
CheckedFile::CheckedFile( const char *input, uint64_t size, ReadChecksumPolicy policy ) :
fileName_( "<StreamBuffer>" ), checkSumPolicy_( policy )
{
bufView_ = new BufferView( input, size );
readOnly_ = true;
physicalLength_ = lseek64( 0LL, SEEK_END );
lseek64( 0, SEEK_SET );
logicalLength_ = physicalToLogical( physicalLength_ );
}
int CheckedFile::open64( const ustring &fileName, int flags, int mode )
{
#if defined( _MSC_VER )
// Handle UTF-8 file names - Windows requires conversion to UTF-16
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::wstring widePath = converter.from_bytes( fileName );
int handle;
int err = _wsopen_s( &handle, widePath.c_str(), flags, _SH_DENYNO, mode );
if ( handle < 0 )
{
throw E57_EXCEPTION2( E57_ERROR_OPEN_FAILED, "err=" + toString( err ) + " fileName=" + fileName +
" flags=" + toString( flags ) + " mode=" + toString( mode ) );
}
return handle;
#elif defined( __GNUC__ )
int result = ::open( fileName_.c_str(), flags, mode );
if ( result < 0 )
{
throw E57_EXCEPTION2( E57_ERROR_OPEN_FAILED, "result=" + toString( result ) + " fileName=" + fileName +
" flags=" + toString( flags ) + " mode=" + toString( mode ) );
}
return result;
#else
#error "no supported compiler defined"
#endif
}
CheckedFile::~CheckedFile()
{
try
{
close(); ///??? what if already closed?
}
catch ( ... )
{
//??? report?
}
}
void CheckedFile::read( char *buf, size_t nRead, size_t /*bufSize*/ )
{
//??? what if read past logical end?, or physical end?
//??? need to keep track of logical length?
//??? check bufSize OK
const uint64_t end = position( Logical ) + nRead;
const uint64_t logicalLength = length( Logical );
if ( end > logicalLength )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "fileName=" + fileName_ + " end=" + toString( end ) +
" length=" + toString( logicalLength ) );
}
uint64_t page = 0;
size_t pageOffset = 0;
getCurrentPageAndOffset( page, pageOffset );
size_t n = std::min( nRead, logicalPageSize - pageOffset );
/// Allocate temp page buffer
std::vector<char> page_buffer_v( physicalPageSize );
char *page_buffer = &page_buffer_v[0];
const auto checksumMod = static_cast<unsigned int>( std::nearbyint( 100.0 / checkSumPolicy_ ) );
while ( nRead > 0 )
{
readPhysicalPage( page_buffer, page );
switch ( checkSumPolicy_ )
{
case CHECKSUM_POLICY_NONE:
break;
case CHECKSUM_POLICY_ALL:
verifyChecksum( page_buffer, page );
break;
default:
if ( !( page % checksumMod ) || ( nRead < physicalPageSize ) )
{
verifyChecksum( page_buffer, page );
}
break;
}
memcpy( buf, page_buffer + pageOffset, n );
buf += n;
nRead -= n;
pageOffset = 0;
++page;
n = std::min( nRead, logicalPageSize );
}
/// When done, leave cursor just past end of last byte read
seek( end, Logical );
}
void CheckedFile::write( const char *buf, size_t nWrite )
{
#ifdef E57_MAX_VERBOSE
// cout << "write nWrite=" << nWrite << " position()="<< position() << std::endl;
// //???
#endif
if ( readOnly_ )
{
throw E57_EXCEPTION2( E57_ERROR_FILE_IS_READ_ONLY, "fileName=" + fileName_ );
}
uint64_t end = position( Logical ) + nWrite;
uint64_t page = 0;
size_t pageOffset = 0;
getCurrentPageAndOffset( page, pageOffset );
size_t n = std::min( nWrite, logicalPageSize - pageOffset );
/// Allocate temp page buffer
std::vector<char> page_buffer_v( physicalPageSize );
char *page_buffer = &page_buffer_v[0];
while ( nWrite > 0 )
{
const uint64_t physicalLength = length( Physical );
if ( page * physicalPageSize < physicalLength )
{
readPhysicalPage( page_buffer, page );
}
#ifdef E57_MAX_VERBOSE
// cout << " page_buffer[0] read: '" << page_buffer[0] << "'" << std::endl;
// cout << "copy " << n << "bytes to page=" << page << " pageOffset=" <<
// pageOffset << " buf='"; //??? for (size_t i=0; i < n; i++) cout <<
// buf[i]; cout << "'" << std::endl;
#endif
memcpy( page_buffer + pageOffset, buf, n );
writePhysicalPage( page_buffer, page );
#ifdef E57_MAX_VERBOSE
// cout << " page_buffer[0] after write: '" << page_buffer[0] << "'" <<
// std::endl; //???
#endif
buf += n;
nWrite -= n;
pageOffset = 0;
page++;
n = std::min( nWrite, logicalPageSize );
}
if ( end > logicalLength_ )
{
logicalLength_ = end;
}
/// When done, leave cursor just past end of buf
seek( end, Logical );
}
CheckedFile &CheckedFile::operator<<( const ustring &s )
{
write( s.c_str(), s.length() ); //??? should be times size of uchar?
return ( *this );
}
CheckedFile &CheckedFile::operator<<( int64_t i )
{
std::stringstream ss;
ss << i;
return ( *this << ss.str() );
}
CheckedFile &CheckedFile::operator<<( uint64_t i )
{
std::stringstream ss;
ss << i;
return ( *this << ss.str() );
}
CheckedFile &CheckedFile::operator<<( float f )
{
//??? is 7 digits right number?
return writeFloatingPoint( f, 7 );
}
CheckedFile &CheckedFile::operator<<( double d )
{
//??? is 17 digits right number?
return writeFloatingPoint( d, 17 );
}
template <class FTYPE> CheckedFile &CheckedFile::writeFloatingPoint( FTYPE value, int precision )
{
#ifdef E57_MAX_VERBOSE
std::cout << "CheckedFile::writeFloatingPoint, value=" << value << " precision=" << precision << std::endl;
#endif
std::stringstream ss;
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
ustring s = ss.str();
const size_t len = s.length();
#ifdef E57_MAX_DEBUG
ustring old_s = s;
#endif
/// Split into mantissa and exponent
/// E.g. 1.23456000000000000e+005 ==> "1.23456000000000000" + "e+005"
ustring mantissa = s.substr( 0, len - 5 );
ustring exponent = s.substr( len - 5, 5 );
/// Double check that we understand the formatting
if ( exponent[0] == 'e' )
{
/// Trim of any trailing zeros in mantissa
while ( mantissa[mantissa.length() - 1] == '0' )
{
mantissa = mantissa.substr( 0, mantissa.length() - 1 );
}
/// Make one attempt to trim off trailing decimal point
if ( mantissa[mantissa.length() - 1] == '.' )
{
mantissa = mantissa.substr( 0, mantissa.length() - 1 );
}
/// Reassemble whole floating point number
/// Check if can drop exponent.
if ( exponent == "e+000" )
{
s = mantissa;
}
else
{
s = mantissa + exponent;
}
}
// Disable these checks because they compare floats using "!=" which is
// invalid
#if 0 // E57_MAX_DEBUG
/// Double check same value
FTYPE old_value = static_cast<FTYPE>(atof(old_s.c_str()));
FTYPE new_value = static_cast<FTYPE>(atof(s.c_str()));
if (old_value != new_value)
throw E57_EXCEPTION2(E57_ERROR_INTERNAL, "fileName=" + fileName_ + " oldValue=" + toString(old_value) + " newValue=" + toString(new_value));
if (new_value != value)
throw E57_EXCEPTION2(E57_ERROR_INTERNAL, "fileName=" + fileName_ + " newValue=" + toString(new_value) + " value=" + toString(value));
#endif
return ( *this << s );
}
void CheckedFile::seek( uint64_t offset, OffsetMode omode )
{
//??? check for seek beyond logicalLength_
const auto pos = static_cast<int64_t>( omode == Physical ? offset : logicalToPhysical( offset ) );
#ifdef E57_MAX_VERBOSE
// cout << "seek offset=" << offset << " omode=" << omode << " pos=" << pos
// << std::endl; //???
#endif
lseek64( pos, SEEK_SET );
}
uint64_t CheckedFile::lseek64( int64_t offset, int whence )
{
if ( ( fd_ < 0 ) && bufView_ )
{
const auto uoffset = static_cast<uint64_t>( offset );
if ( bufView_->seek( uoffset, whence ) )
{
return bufView_->pos();
}
throw E57_EXCEPTION2( E57_ERROR_LSEEK_FAILED, "fileName=" + fileName_ + " offset=" + toString( offset ) +
" whence=" + toString( whence ) );
}
#if defined( _WIN32 )
#if defined( _MSC_VER ) || defined( __MINGW32__ ) //<rs 2010-06-16> mingw _is_ WIN32!
__int64 result = _lseeki64( fd_, offset, whence );
#elif defined( __GNUC__ ) //<rs 2010-06-16> this most likely will not get
// triggered (cygwin != WIN32)?
#ifdef E57_MAX_DEBUG
if ( sizeof( off_t ) != sizeof( offset ) )
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "sizeof(off_t)=" + toString( sizeof( off_t ) ) );
#endif
int64_t result = ::lseek( fd_, offset, whence );
#else
#error "no supported compiler defined"
#endif
#elif defined( __linux__ )
int64_t result = ::lseek64( fd_, offset, whence );
#elif defined( __APPLE__ ) || defined(__BSD)
int64_t result = ::lseek( fd_, offset, whence );
#else
#error "no supported OS platform defined"
#endif
if ( result < 0 )
{
throw E57_EXCEPTION2( E57_ERROR_LSEEK_FAILED, "fileName=" + fileName_ + " offset=" + toString( offset ) +
" whence=" + toString( whence ) +
" result=" + toString( result ) );
}
return static_cast<uint64_t>( result );
}
uint64_t CheckedFile::position( OffsetMode omode )
{
/// Get current file cursor position
const uint64_t pos = lseek64( 0LL, SEEK_CUR );
if ( omode == Physical )
{
return pos;
}
return physicalToLogical( pos );
}
uint64_t CheckedFile::length( OffsetMode omode )
{
if ( omode == Physical )
{
if ( readOnly_ )
{
return physicalLength_;
}
// Current file position
uint64_t original_pos = lseek64( 0LL, SEEK_CUR );
// End file position
uint64_t end_pos = lseek64( 0LL, SEEK_END );
// Restore original position
lseek64( original_pos, SEEK_SET );
return end_pos;
}
return logicalLength_;
}
void CheckedFile::extend( uint64_t newLength, OffsetMode omode )
{
#ifdef E57_MAX_VERBOSE
// cout << "extend newLength=" << newLength << " omode="<< omode << std::endl;
// //???
#endif
if ( readOnly_ )
{
throw E57_EXCEPTION2( E57_ERROR_FILE_IS_READ_ONLY, "fileName=" + fileName_ );
}
uint64_t newLogicalLength = 0;
if ( omode == Physical )
{
newLogicalLength = physicalToLogical( newLength );
}
else
{
newLogicalLength = newLength;
}
uint64_t currentLogicalLength = length( Logical );
/// Make sure we are trying to make file longer
if ( newLogicalLength < currentLogicalLength )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "fileName=" + fileName_ + " newLength=" + toString( newLogicalLength ) +
" currentLength=" + toString( currentLogicalLength ) );
}
/// Calc how may zero bytes we have to add to end
uint64_t nWrite = newLogicalLength - currentLogicalLength;
/// Seek to current end of file
seek( currentLogicalLength, Logical );
uint64_t page = 0;
size_t pageOffset = 0;
getCurrentPageAndOffset( page, pageOffset );
/// Calc first write size (may be partial page)
/// Watch out for different int sizes here.
size_t n = 0;
if ( nWrite < logicalPageSize - pageOffset )
{
n = static_cast<size_t>( nWrite );
}
else
{
n = logicalPageSize - pageOffset;
}
/// Allocate temp page buffer
std::vector<char> page_buffer_v( physicalPageSize );
char *page_buffer = &page_buffer_v[0];
while ( nWrite > 0 )
{
const uint64_t physicalLength = length( Physical );
if ( page * physicalPageSize < physicalLength )
{
readPhysicalPage( page_buffer, page );
}
#ifdef E57_MAX_VERBOSE
// cout << "extend " << n << "bytes on page=" << page << " pageOffset=" <<
// pageOffset << std::endl;
// //???
#endif
memset( page_buffer + pageOffset, 0, n );
writePhysicalPage( page_buffer, page );
nWrite -= n;
pageOffset = 0;
++page;
if ( nWrite < logicalPageSize )
{
n = static_cast<size_t>( nWrite );
}
else
{
n = logicalPageSize;
}
}
//??? what if loop above throws, logicalLength_ may be wrong
logicalLength_ = newLogicalLength;
/// When done, leave cursor at end of file
seek( newLogicalLength, Logical );
}
void CheckedFile::close()
{
if ( fd_ >= 0 )
{
#if defined( _MSC_VER )
int result = ::_close( fd_ );
#elif defined( __GNUC__ )
int result = ::close( fd_ );
#else
#error "no supported compiler defined"
#endif
if ( result < 0 )
{
throw E57_EXCEPTION2( E57_ERROR_CLOSE_FAILED, "fileName=" + fileName_ + " result=" + toString( result ) );
}
fd_ = -1;
}
if ( bufView_ )
{
delete bufView_;
bufView_ = nullptr;
// WARNING: do NOT delete buffer of bufView_ because
// pointer is handled by user !!
}
}
void CheckedFile::unlink()
{
close();
/// Try to remove the file, don't report a failure
int result = std::remove( fileName_.c_str() ); //??? unicode support here
(void)result; // this maybe unused
#ifdef E57_MAX_VERBOSE
if ( result < 0 )
{
std::cout << "std::remove() failed, result=" << result << std::endl;
}
#endif
}
inline uint32_t swap_uint32( uint32_t val )
{
val = ( ( val << 8 ) & 0xFF00FF00 ) | ( ( val >> 8 ) & 0xFF00FF );
return ( val << 16 ) | ( val >> 16 );
}
/// Calc CRC32C of given data
uint32_t CheckedFile::checksum( char *buf, size_t size ) const
{
static const CRC::Parameters<crcpp_uint32, 32> sCRCParams{ 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true };
static const CRC::Table<crcpp_uint32, 32> sCRCTable = sCRCParams.MakeTable();
auto crc = CRC::Calculate<crcpp_uint32, 32>( buf, size, sCRCTable );
// (Andy) I don't understand why we need to swap bytes here
crc = swap_uint32( crc );
return crc;
}
void CheckedFile::verifyChecksum( char *page_buffer, size_t page )
{
const uint32_t check_sum = checksum( page_buffer, logicalPageSize );
const uint32_t check_sum_in_page = *reinterpret_cast<uint32_t *>( &page_buffer[logicalPageSize] );
if ( check_sum_in_page != check_sum )
{
const uint64_t physicalLength = length( Physical );
throw E57_EXCEPTION2( E57_ERROR_BAD_CHECKSUM,
"fileName=" + fileName_ + " computedChecksum=" + toString( check_sum ) +
" storedChecksum=" + toString( check_sum_in_page ) + " page=" + toString( page ) +
" length=" + toString( physicalLength ) );
}
}
void CheckedFile::getCurrentPageAndOffset( uint64_t &page, size_t &pageOffset, OffsetMode omode )
{
const uint64_t pos = position( omode );
if ( omode == Physical )
{
page = pos >> physicalPageSizeLog2;
pageOffset = static_cast<size_t>( pos & physicalPageSizeMask );
}
else
{
page = pos / logicalPageSize;
pageOffset = static_cast<size_t>( pos - page * logicalPageSize );
}
}
void CheckedFile::readPhysicalPage( char *page_buffer, uint64_t page )
{
#ifdef E57_MAX_VERBOSE
// cout << "readPhysicalPage, page:" << page << std::endl;
#endif
#ifdef E57_CHECK_FILE_DEBUG
const uint64_t physicalLength = length( Physical );
assert( page * physicalPageSize < physicalLength );
#endif
/// Seek to start of physical page
seek( page * physicalPageSize, Physical );
if ( ( fd_ < 0 ) && bufView_ )
{
bufView_->read( page_buffer, physicalPageSize );
return;
}
#if defined( _MSC_VER )
int result = ::_read( fd_, page_buffer, physicalPageSize );
#elif defined( __GNUC__ )
ssize_t result = ::read( fd_, page_buffer, physicalPageSize );
#else
#error "no supported compiler defined"
#endif
if ( result < 0 || static_cast<size_t>( result ) != physicalPageSize )
{
throw E57_EXCEPTION2( E57_ERROR_READ_FAILED, "fileName=" + fileName_ + " result=" + toString( result ) );
}
}
void CheckedFile::writePhysicalPage( char *page_buffer, uint64_t page )
{
#ifdef E57_MAX_VERBOSE
// cout << "writePhysicalPage, page:" << page << std::endl;
#endif
/// Append checksum
uint32_t check_sum = checksum( page_buffer, logicalPageSize );
*reinterpret_cast<uint32_t *>( &page_buffer[logicalPageSize] ) = check_sum; //??? little endian dependency
/// Seek to start of physical page
seek( page * physicalPageSize, Physical );
#if defined( _MSC_VER )
int result = ::_write( fd_, page_buffer, physicalPageSize );
#elif defined( __GNUC__ )
ssize_t result = ::write( fd_, page_buffer, physicalPageSize );
#else
#error "no supported compiler defined"
#endif
if ( result < 0 )
{
throw E57_EXCEPTION2( E57_ERROR_WRITE_FAILED, "fileName=" + fileName_ + " result=" + toString( result ) );
}
}

View File

@@ -1,128 +0,0 @@
/*
* 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 );
}
}

View File

@@ -1,39 +0,0 @@
// SPDX-License-Identifier: BSL-1.0
// Copyright (c) 2020 PTC Inc.
#include "Common.h"
#include <random>
namespace e57
{
std::string generateRandomGUID()
{
static constexpr const char UUID_CHARS[] = "0123456789ABCDEF";
static std::random_device rd;
static std::mt19937 gen( rd() );
static std::uniform_int_distribution<> dis( 0, 15 /* number of chars in UUID_CHARS */ );
std::string uuid( 38, ' ' );
uuid[0] = '{';
uuid[9] = '-';
uuid[14] = '-';
uuid[19] = '-';
uuid[24] = '-';
uuid[37] = '}';
uuid[15] = '4';
for ( int i = 1; i < 37; ++i )
{
if ( i != 9 && i != 14 && i != 19 && i != 24 && i != 15 )
{
uuid[i] = UUID_CHARS[dis( gen )];
}
}
return uuid;
}
} // end namespace e57

View File

@@ -1,183 +0,0 @@
/*
* 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();
}

View File

@@ -1,360 +0,0 @@
/*
* 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.
*/
#include "CompressedVectorNodeImpl.h"
#include "CheckedFile.h"
#include "CompressedVectorReaderImpl.h"
#include "CompressedVectorWriterImpl.h"
#include "ImageFileImpl.h"
#include "VectorNodeImpl.h"
namespace e57
{
CompressedVectorNodeImpl::CompressedVectorNodeImpl( ImageFileImplWeakPtr destImageFile ) : NodeImpl( destImageFile )
{
// don't checkImageFileOpen, NodeImpl() will do it
}
void CompressedVectorNodeImpl::setPrototype( const NodeImplSharedPtr &prototype )
{
// don't checkImageFileOpen, ctor did it
//??? check ok for proto, no Blob CompressedVector, empty?
//??? throw E57_EXCEPTION2(E57_ERROR_BAD_PROTOTYPE)
/// Can't set prototype twice.
if ( prototype_ )
{
throw E57_EXCEPTION2( E57_ERROR_SET_TWICE, "this->pathName=" + this->pathName() );
}
/// 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() );
}
/// 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() );
}
//!!! 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).
}
NodeImplSharedPtr CompressedVectorNodeImpl::getPrototype() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( prototype_ ); //??? check defined
}
void CompressedVectorNodeImpl::setCodecs( const std::shared_ptr<VectorNodeImpl> &codecs )
{
// don't checkImageFileOpen, ctor did it
//??? check ok for codecs, empty vector, or each element has "inputs" vector
// of strings, codec
// substruct
/// Can't set codecs twice.
if ( codecs_ )
{
throw E57_EXCEPTION2( E57_ERROR_SET_TWICE, "this->pathName=" + this->pathName() );
}
/// 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() );
}
/// 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() );
}
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).
}
std::shared_ptr<VectorNodeImpl> CompressedVectorNodeImpl::getCodecs() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( codecs_ ); //??? check defined
}
bool CompressedVectorNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
{
// don't checkImageFileOpen
//??? is this test a good idea?
/// Same node type?
if ( ni->type() != E57_COMPRESSED_VECTOR )
{
return ( false );
}
std::shared_ptr<CompressedVectorNodeImpl> cvi( std::static_pointer_cast<CompressedVectorNodeImpl>( ni ) );
/// recordCount must match
if ( recordCount_ != cvi->recordCount_ )
{
return ( false );
}
/// Prototypes and codecs must match ???
if ( !prototype_->isTypeEquivalent( cvi->prototype_ ) )
{
return ( false );
}
if ( !codecs_->isTypeEquivalent( cvi->codecs_ ) )
{
return ( false );
}
return ( true );
}
bool CompressedVectorNodeImpl::isDefined( const ustring &pathName )
{
throw E57_EXCEPTION2( E57_ERROR_NOT_IMPLEMENTED, "this->pathName=" + this->pathName() + " pathName=" + pathName );
}
void CompressedVectorNodeImpl::setAttachedRecursive()
{
/// Mark this node as attached to an ImageFile
isAttached_ = true;
/// Mark nodes in prototype tree, if defined
if ( prototype_ )
{
prototype_->setAttachedRecursive();
}
/// Mark nodes in codecs tree if defined
if ( codecs_ )
{
codecs_->setAttachedRecursive();
}
}
int64_t CompressedVectorNodeImpl::childCount() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( recordCount_ );
}
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() );
}
void CompressedVectorNodeImpl::writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
const char *forcedFieldName )
{
// don't checkImageFileOpen
ustring fieldName;
if ( forcedFieldName )
{
fieldName = forcedFieldName;
}
else
{
fieldName = elementName_;
}
uint64_t physicalStart = cf.logicalToPhysical( binarySectionLogicalStart_ );
cf << space( indent ) << "<" << fieldName << " type=\"CompressedVector\"";
cf << " fileOffset=\"" << physicalStart;
cf << "\" recordCount=\"" << recordCount_ << "\">\n";
if ( prototype_ )
{
prototype_->writeXml( imf, cf, indent + 2, "prototype" );
}
if ( codecs_ )
{
codecs_->writeXml( imf, cf, indent + 2, "codecs" );
}
cf << space( indent ) << "</" << fieldName << ">\n";
}
#ifdef E57_DEBUG
void CompressedVectorNodeImpl::dump( int indent, std::ostream &os ) const
{
os << space( indent ) << "type: CompressedVector"
<< " (" << type() << ")" << std::endl;
NodeImpl::dump( indent, os );
if ( prototype_ )
{
os << space( indent ) << "prototype:" << std::endl;
prototype_->dump( indent + 2, os );
}
else
{
os << space( indent ) << "prototype: <empty>" << std::endl;
}
if ( codecs_ )
{
os << space( indent ) << "codecs:" << std::endl;
codecs_->dump( indent + 2, os );
}
else
{
os << space( indent ) << "codecs: <empty>" << std::endl;
}
os << space( indent ) << "recordCount: " << recordCount_ << std::endl;
os << space( indent ) << "binarySectionLogicalStart: " << binarySectionLogicalStart_ << std::endl;
}
#endif
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
if ( destImageFile->writerCount() > 0 )
{
throw E57_EXCEPTION2( E57_ERROR_TOO_MANY_WRITERS,
"fileName=" + destImageFile->fileName() +
" writerCount=" + toString( destImageFile->writerCount() ) +
" readerCount=" + toString( destImageFile->readerCount() ) );
}
if ( destImageFile->readerCount() > 0 )
{
throw E57_EXCEPTION2( E57_ERROR_TOO_MANY_READERS,
"fileName=" + destImageFile->fileName() +
" writerCount=" + toString( destImageFile->writerCount() ) +
" readerCount=" + toString( destImageFile->readerCount() ) );
}
/// sbufs can't be empty
if ( sbufs.empty() )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT, "fileName=" + destImageFile->fileName() );
}
if ( !destImageFile->isWriter() )
{
throw E57_EXCEPTION2( E57_ERROR_FILE_IS_READ_ONLY, "fileName=" + destImageFile->fileName() );
}
if ( !isAttached() )
{
throw E57_EXCEPTION2( E57_ERROR_NODE_UNATTACHED, "fileName=" + destImageFile->fileName() );
}
/// 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 ) );
/// 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 )
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
ImageFileImplSharedPtr destImageFile( destImageFile_ );
/// Check don't have any writers/readers open for this ImageFile
if ( destImageFile->writerCount() > 0 )
{
throw E57_EXCEPTION2( E57_ERROR_TOO_MANY_WRITERS,
"fileName=" + destImageFile->fileName() +
" writerCount=" + toString( destImageFile->writerCount() ) +
" readerCount=" + toString( destImageFile->readerCount() ) );
}
if ( destImageFile->readerCount() > 0 )
{
throw E57_EXCEPTION2( E57_ERROR_TOO_MANY_READERS,
"fileName=" + destImageFile->fileName() +
" writerCount=" + toString( destImageFile->writerCount() ) +
" readerCount=" + toString( destImageFile->readerCount() ) );
}
/// dbufs can't be empty
if ( dbufs.empty() )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT, "fileName=" + destImageFile->fileName() );
}
/// Can be read or write mode, but must be attached
if ( !isAttached() )
{
throw E57_EXCEPTION2( E57_ERROR_NODE_UNATTACHED, "fileName=" + destImageFile->fileName() );
}
/// Get pointer to me (really shared_ptr<CompressedVectorNodeImpl>)
NodeImplSharedPtr ni( shared_from_this() );
#ifdef E57_MAX_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
// 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 ( cvri );
}
}

View File

@@ -1,93 +0,0 @@
#pragma once
/*
* 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.
*/
#include "NodeImpl.h"
namespace e57
{
class CompressedVectorNodeImpl : public NodeImpl
{
public:
CompressedVectorNodeImpl( ImageFileImplWeakPtr destImageFile );
~CompressedVectorNodeImpl() override = default;
NodeType type() const override
{
return E57_COMPRESSED_VECTOR;
}
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
bool isDefined( const ustring &pathName ) override;
void setAttachedRecursive() override;
void setPrototype( const NodeImplSharedPtr &prototype );
NodeImplSharedPtr getPrototype() const;
void setCodecs( const std::shared_ptr<VectorNodeImpl> &codecs );
std::shared_ptr<VectorNodeImpl> getCodecs() const;
int64_t childCount() const;
void checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin ) override;
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
const char *forcedFieldName = nullptr ) override;
/// Iterator constructors
std::shared_ptr<CompressedVectorWriterImpl> writer( std::vector<SourceDestBuffer> sbufs );
std::shared_ptr<CompressedVectorReaderImpl> reader( std::vector<SourceDestBuffer> dbufs );
int64_t getRecordCount() const
{
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
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
private:
friend class CompressedVectorReaderImpl;
NodeImplSharedPtr prototype_;
std::shared_ptr<VectorNodeImpl> codecs_;
int64_t recordCount_ = 0;
uint64_t binarySectionLogicalStart_ = 0;
};
}

View File

@@ -1,607 +0,0 @@
/*
* 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.
*/
#include "CompressedVectorReaderImpl.h"
#include "CheckedFile.h"
#include "CompressedVectorNodeImpl.h"
#include "ImageFileImpl.h"
#include "Packet.h"
#include "SectionHeaders.h"
#include "SourceDestBufferImpl.h"
namespace e57
{
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
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?
/// Empty dbufs is an error
if ( dbufs.empty() )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT,
"imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName() );
}
/// Get CompressedArray's prototype node (all array elements must match this
/// type)
proto_ = cVector_->getPrototype();
/// Check dbufs well formed (matches proto exactly)
setBuffers( dbufs );
/// 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() );
/// 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 ) );
}
channels_.emplace_back( dbufs.at( i ), decoder, static_cast<unsigned>( bytestreamNumber ),
cVector_->childCount() );
}
recordCount_ = 0;
/// 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;
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() );
}
imf->file_->seek( sectionLogicalStart, CheckedFile::Logical );
imf->file_->read( reinterpret_cast<char *>( &sectionHeader ), sizeof( sectionHeader ) );
#ifdef E57_DEBUG
sectionHeader.verify( imf->file_->length( CheckedFile::Physical ) );
#endif
/// 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 );
/// 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
if ( dpkt->header.packetType != DATA_PACKET )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( dpkt->header.packetType ) );
}
/// Have good packet, initialize channels
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?
imf->incrReaderCount();
/// If get here, the reader is open
isOpen_ = true;
}
CompressedVectorReaderImpl::~CompressedVectorReaderImpl()
{
#ifdef E57_MAX_VERBOSE
std::cout << "~CompressedVectorReaderImpl() called" << std::endl; //???
// dump(4);
#endif
if ( isOpen_ )
{
try
{
close(); ///??? what if already closed?
}
catch ( ... )
{
//??? report?
}
}
}
void CompressedVectorReaderImpl::setBuffers( std::vector<SourceDestBuffer> &dbufs )
{
/// don't checkImageFileOpen
/// don't checkReaderOpen
/// 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 ( !dbufs_.empty() )
{
if ( dbufs_.size() != dbufs.size() )
{
throw E57_EXCEPTION2( E57_ERROR_BUFFERS_NOT_COMPATIBLE,
"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
oldBuf->checkCompatible( newBuf );
}
}
dbufs_ = dbufs;
}
unsigned CompressedVectorReaderImpl::read( std::vector<SourceDestBuffer> &dbufs )
{
/// don't checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__), read() will
/// do it
checkReaderOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
/// Check compatible with current dbufs
setBuffers( dbufs );
return ( read() );
}
unsigned CompressedVectorReaderImpl::read()
{
#ifdef E57_MAX_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
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.
for ( auto &channel : channels_ )
{
channel.decoder->inputProcess( nullptr, 0 );
}
/// 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.
uint64_t earliestPacketLogicalOffset = earliestPacketNeededForInput();
/// If nobody's hungry, we are done with the read
if ( earliestPacketLogicalOffset == E57_UINT64_MAX )
{
break;
}
/// Feed packet to the hungry decoders
feedPacketToDecoders( earliestPacketLogicalOffset );
}
/// Verify that each channel produced the same number of records
unsigned outputCount = 0;
for ( unsigned i = 0; i < channels_.size(); i++ )
{
DecodeChannel *chan = &channels_[i];
if ( i == 0 )
{
outputCount = chan->dbuf.impl()->nextIndex();
}
else
{
if ( outputCount != chan->dbuf.impl()->nextIndex() )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "outputCount=" + toString( outputCount ) + " nextIndex=" +
toString( chan->dbuf.impl()->nextIndex() ) );
}
}
}
/// 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
unsigned earliestChannel = 0;
#endif
for ( unsigned i = 0; i < channels_.size(); i++ )
{
const DecodeChannel *chan = &channels_[i];
/// 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
if ( chan->currentPacketLogicalOffset < earliestPacketLogicalOffset )
{
earliestPacketLogicalOffset = chan->currentPacketLogicalOffset;
#ifdef E57_MAX_VERBOSE
earliestChannel = i;
#endif
}
}
}
#ifdef E57_MAX_VERBOSE
if ( earliestPacketLogicalOffset == E57_UINT64_MAX )
{
std::cout << "earliestPacketNeededForInput returning none found" << std::endl;
}
else
{
std::cout << "earliestPacketNeededForInput returning " << earliestPacketLogicalOffset << " for channel["
<< earliestChannel << "]" << std::endl;
}
#endif
return earliestPacketLogicalOffset;
}
DataPacket *CompressedVectorReaderImpl::dataPacket( uint64_t inLogicalOffset ) const
{
char *packet = nullptr;
std::unique_ptr<PacketLock> packetLock = cache_->lock( inLogicalOffset, packet );
return reinterpret_cast<DataPacket *>( packet );
}
inline bool _alreadyReadPacket( const DecodeChannel &channel, uint64_t currentPacketLogicalOffset )
{
return ( ( channel.currentPacketLogicalOffset != currentPacketLogicalOffset ) || channel.isOutputBlocked() );
}
void CompressedVectorReaderImpl::feedPacketToDecoders( uint64_t currentPacketLogicalOffset )
{
// Get packet at currentPacketLogicalOffset into memory.
auto dpkt = dataPacket( currentPacketLogicalOffset );
// 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 ) );
}
// Read earliest packet into cache and send data to decoders with unblocked
// output
bool anyChannelHasExhaustedPacket = false;
uint64_t nextPacketLogicalOffset = E57_UINT64_MAX;
// 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.
if ( _alreadyReadPacket( channel, currentPacketLogicalOffset ) )
{
continue;
}
// Get bytestream buffer for this channel from packet
unsigned int bsbLength = 0;
const char *bsbStart = dpkt->getBytestream( channel.bytestreamNumber, bsbLength );
// 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 ) );
}
// Calc where we are in the buffer
const char *uneatenStart = &bsbStart[channel.currentBytestreamBufferIndex];
const size_t uneatenLength = bsbLength - channel.currentBytestreamBufferIndex;
if ( &uneatenStart[uneatenLength] > &bsbStart[bsbLength] )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "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;
if ( uneatenLength == 0 )
{
channel.dump( 8 );
}
std::cout << " stream[" << channel.bytestreamNumber << "]: bytesProcessed=" << bytesProcessed << std::endl;
#endif
// Adjust counts of bytestream location
channel.currentBytestreamBufferIndex += bytesProcessed;
// Check if this channel has exhausted its bytestream buffer in this
// packet
if ( channel.isInputBlocked() )
{
#ifdef E57_MAX_VERBOSE
std::cout << " stream[" << channel.bytestreamNumber << "] has exhausted its input in current packet"
<< std::endl;
#endif
anyChannelHasExhaustedPacket = true;
nextPacketLogicalOffset = currentPacketLogicalOffset + dpkt->header.packetLogicalLengthMinus1 + 1;
}
}
// Skip over any index or empty packets to next data packet.
nextPacketLogicalOffset = findNextDataPacket( nextPacketLogicalOffset );
// If no channel is exhausted, we're done
if ( !anyChannelHasExhaustedPacket )
{
return;
}
// Some channel has exhausted this packet, so find next data packet and
// update currentPacketLogicalOffset for all interested channels.
if ( nextPacketLogicalOffset < E57_UINT64_MAX )
{ //??? huh?
// Get packet at nextPacketLogicalOffset into memory.
dpkt = dataPacket( nextPacketLogicalOffset );
// Got a data packet, update the channels with exhausted input
for ( DecodeChannel &channel : channels_ )
{
// Skip channels that have already read this packet.
if ( _alreadyReadPacket( channel, currentPacketLogicalOffset ) )
{
continue;
}
channel.currentPacketLogicalOffset = nextPacketLogicalOffset;
channel.currentBytestreamBufferIndex = 0;
// 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 );
#ifdef E57_MAX_VERBOSE
std::cout << " set new stream buffer for channel[" << channel.bytestreamNumber
<< "], length=" << channel.currentBytestreamBufferLength << std::endl;
#endif
// ??? perform flush if new packet flag set?
}
}
else
{
// Reached end without finding data packet, mark exhausted channels as
// finished
#ifdef E57_MAX_VERBOSE
std::cout << " at end of data packets" << std::endl;
#endif
if ( nextPacketLogicalOffset >= sectionEndLogicalOffset_ )
{
for ( DecodeChannel &channel : channels_ )
{
// Skip channels that have already read this packet.
if ( _alreadyReadPacket( channel, currentPacketLogicalOffset ) )
{
continue;
}
#ifdef E57_MAX_VERBOSE
std::cout << " Marking channel[" << channel.bytestreamNumber << "] as finished" << std::endl;
#endif
channel.inputFinished = true;
}
}
}
}
uint64_t CompressedVectorReaderImpl::findNextDataPacket( uint64_t nextPacketLogicalOffset )
{
#ifdef E57_MAX_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.
while ( nextPacketLogicalOffset < sectionEndLogicalOffset_ )
{
char *anyPacket = nullptr;
std::unique_ptr<PacketLock> packetLock = cache_->lock( nextPacketLogicalOffset, anyPacket );
/// 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;
#endif
return nextPacketLogicalOffset;
}
/// 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;
}
void CompressedVectorReaderImpl::seek( uint64_t /*recordNumber*/ )
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
///!!! implement
throw E57_EXCEPTION1( E57_ERROR_NOT_IMPLEMENTED );
}
bool CompressedVectorReaderImpl::isOpen() const
{
/// don't checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__), or
/// checkReaderOpen()
return ( isOpen_ );
}
std::shared_ptr<CompressedVectorNodeImpl> CompressedVectorReaderImpl::compressedVectorNode() const
{
return ( cVector_ );
}
void CompressedVectorReaderImpl::close()
{
/// 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
if ( !isOpen_ )
{
return;
}
/// Destroy decoders
channels_.clear();
delete cache_;
cache_ = nullptr;
isOpen_ = false;
}
void CompressedVectorReaderImpl::checkImageFileOpen( const char *srcFileName, int srcLineNumber,
const char *srcFunctionName ) const
{
// unimplemented...
(void)srcFileName; (void)srcLineNumber; (void)srcFunctionName;
}
void CompressedVectorReaderImpl::checkReaderOpen( const char *srcFileName, int srcLineNumber,
const char *srcFunctionName ) const
{
if ( !isOpen_ )
{
throw E57Exception( E57_ERROR_READER_NOT_OPEN,
"imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName(),
srcFileName, srcLineNumber, srcFunctionName );
}
}
#ifdef E57_DEBUG
void CompressedVectorReaderImpl::dump( int indent, std::ostream &os )
{
os << space( indent ) << "isOpen:" << isOpen_ << std::endl;
for ( unsigned i = 0; i < dbufs_.size(); i++ )
{
os << space( indent ) << "dbufs[" << i << "]:" << std::endl;
dbufs_[i].dump( indent + 4, os );
}
os << space( indent ) << "cVector:" << std::endl;
cVector_->dump( indent + 4, os );
os << space( indent ) << "proto:" << std::endl;
proto_->dump( indent + 4, os );
for ( unsigned i = 0; i < channels_.size(); i++ )
{
os << space( indent ) << "channels[" << i << "]:" << std::endl;
channels_[i].dump( indent + 4, os );
}
os << space( indent ) << "recordCount: " << recordCount_ << std::endl;
os << space( indent ) << "maxRecordCount: " << maxRecordCount_ << std::endl;
os << space( indent ) << "sectionEndLogicalOffset: " << sectionEndLogicalOffset_ << std::endl;
}
#endif
}

View File

@@ -1,75 +0,0 @@
#pragma once
/*
* 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.
*/
#include "DecodeChannel.h"
namespace e57
{
class DataPacket;
class PacketReadCache;
class CompressedVectorReaderImpl
{
public:
CompressedVectorReaderImpl( std::shared_ptr<CompressedVectorNodeImpl> ni, std::vector<SourceDestBuffer> &dbufs );
~CompressedVectorReaderImpl();
unsigned read();
unsigned read( std::vector<SourceDestBuffer> &dbufs );
void seek( uint64_t recordNumber );
bool isOpen() const;
std::shared_ptr<CompressedVectorNodeImpl> compressedVectorNode() const;
void close();
#ifdef E57_DEBUG
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 setBuffers( std::vector<SourceDestBuffer> &dbufs ); //???needed?
uint64_t earliestPacketNeededForInput() const;
DataPacket *dataPacket( uint64_t inLogicalOffset ) const;
void feedPacketToDecoders( uint64_t currentPacketLogicalOffset );
uint64_t findNextDataPacket( uint64_t nextPacketLogicalOffset );
//??? no default ctor, copy, assignment?
bool isOpen_;
std::vector<SourceDestBuffer> dbufs_;
std::shared_ptr<CompressedVectorNodeImpl> cVector_;
NodeImplSharedPtr proto_;
std::vector<DecodeChannel> channels_;
PacketReadCache *cache_;
uint64_t recordCount_; /// number of records written so far
uint64_t maxRecordCount_;
uint64_t sectionEndLogicalOffset_;
};
}

View File

@@ -1,661 +0,0 @@
/*
* 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.
*/
#include <cmath>
#include <numeric>
#include "CheckedFile.h"
#include "CompressedVectorNodeImpl.h"
#include "CompressedVectorWriterImpl.h"
#include "ImageFileImpl.h"
#include "SectionHeaders.h"
#include "SourceDestBufferImpl.h"
namespace e57
{
struct SortByBytestreamNumber
{
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
{
//??? check if cvector already been written (can't write twice)
/// Empty sbufs is an error
if ( sbufs.empty() )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT,
"imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName() );
}
/// Get CompressedArray's prototype node (all array elements must match this
/// type)
proto_ = cVector_->getPrototype();
/// 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 ( unsigned i = 0; i < sbufs_.size(); i++ )
{
/// 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.
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 ) );
}
/// 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.
sort( bytestreams_.begin(), bytestreams_.end(), SortByBytestreamNumber() );
#ifdef E57_MAX_DEBUG
/// 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() ) );
}
}
#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 );
sectionLogicalLength_ = 0;
dataPhysicalOffset_ = 0;
topIndexPhysicalOffset_ = 0;
recordCount_ = 0;
dataPacketsCount_ = 0;
indexPacketsCount_ = 0;
/// 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
isOpen_ = true;
}
CompressedVectorWriterImpl::~CompressedVectorWriterImpl()
{
#ifdef E57_MAX_VERBOSE
std::cout << "~CompressedVectorWriterImpl() called" << std::endl; //???
#endif
try
{
if ( isOpen_ )
{
close();
}
}
catch ( ... )
{
//??? report?
}
}
void CompressedVectorWriterImpl::close()
{
#ifdef E57_MAX_VERBOSE
std::cout << "CompressedVectorWriterImpl::close() called" << std::endl; //???
#endif
ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
/// Before anything that can throw, decrement writer count
imf->decrWriterCount();
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
/// 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.
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().
flush();
while ( totalOutputAvailable() > 0 )
{
packetWrite();
flush();
}
/// 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
std::cout << " sectionLogicalLength_=" << sectionLogicalLength_ << std::endl; //???
#endif
/// 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
std::cout << " CompressedVectorSectionHeader:" << std::endl;
header.dump( 4 ); //???
#endif
#ifdef E57_DEBUG
/// Verify OK before write it.
header.verify( imf->file_->length( CheckedFile::Physical ) );
#endif
/// 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
cVector_->setRecordCount( recordCount_ );
cVector_->setBinarySectionLogicalStart( sectionHeaderLogicalStart_ );
/// Free channels
bytestreams_.clear();
#ifdef E57_MAX_VERBOSE
std::cout << " CompressedVectorWriter:" << std::endl;
dump( 4 );
#endif
}
bool CompressedVectorWriterImpl::isOpen() const
{
/// don't checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__), or
/// checkWriterOpen()
return isOpen_;
}
std::shared_ptr<CompressedVectorNodeImpl> CompressedVectorWriterImpl::compressedVectorNode() const
{
return cVector_;
}
void CompressedVectorWriterImpl::setBuffers( std::vector<SourceDestBuffer> &sbufs )
{
/// don't checkImageFileOpen
/// 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() ) );
}
for ( size_t i = 0; i < sbufs_.size(); ++i )
{
std::shared_ptr<SourceDestBufferImpl> oldbuf = sbufs_[i].impl();
std::shared_ptr<SourceDestBufferImpl> newBuf = sbufs[i].impl();
/// 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.
proto_->checkBuffers( sbufs, false );
sbufs_ = sbufs;
}
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
setBuffers( sbufs );
write( requestedRecordCount );
}
void CompressedVectorWriterImpl::write( const size_t requestedRecordCount )
{
#ifdef E57_MAX_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() )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT,
"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
uint64_t endRecordIndex = recordCount_ + requestedRecordCount;
while ( true )
{
/// Calc remaining record counts for all channels
uint64_t totalRecordCount = 0;
for ( auto &bytestream : bytestreams_ )
{
totalRecordCount += endRecordIndex - bytestream->currentRecordIndex();
}
#ifdef E57_MAX_VERBOSE
std::cout << " totalRecordCount=" << totalRecordCount << std::endl; //???
#endif
/// 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).
#ifdef E57_MAX_VERBOSE
std::cout << " currentPacketSize()=" << currentPacketSize() << std::endl; //???
#endif
#ifdef E57_WRITE_CRAZY_PACKET_MODE
///??? 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 ( 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)
}
#ifdef E57_MAX_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_ )
{
totalBitsPerRecord += bytestream->bitsPerRecord();
}
const float totalBytesPerRecord = std::max( totalBitsPerRecord / 8, 0.1F ); //??? trust
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. ???
///!!!! 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
uint64_t recordCount = endRecordIndex - bytestream->currentRecordIndex();
recordCount = ( recordCount < 50ULL ) ? recordCount : 50ULL; // min(recordCount, 50ULL);
bytestream->processRecords( static_cast<unsigned>( recordCount ) );
}
}
}
recordCount_ += requestedRecordCount;
/// 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
{
size_t total = 0;
for ( const auto &bytestream : bytestreams_ )
{
total += bytestream->outputAvailable();
}
return total;
}
size_t CompressedVectorWriterImpl::currentPacketSize() const
{
/// Calc current packet size
return ( sizeof( DataPacketHeader ) + bytestreams_.size() * sizeof( uint16_t ) + totalOutputAvailable() );
}
uint64_t CompressedVectorWriterImpl::packetWrite()
{
#ifdef E57_MAX_VERBOSE
std::cout << "CompressedVectorWriterImpl::packetWrite() called" << std::endl; //???
#endif
/// Double check that we have work to do
size_t totalOutput = totalOutputAvailable();
if ( totalOutput == 0 )
{
return ( 0 );
}
#ifdef E57_MAX_VERBOSE
std::cout << " totalOutput=" << totalOutput << 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( bytestreams_.size() );
/// See if we can fit into a single data packet
if ( totalOutput < packetMaxPayloadBytes )
{
/// We can fit everything in one packet
for ( unsigned i = 0; i < bytestreams_.size(); i++ )
{
count.at( i ) = bytestreams_.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++ )
{
/// Round down here so sum <= packetMaxPayloadBytes
count.at( i ) =
static_cast<unsigned>( std::floor( fractionToSend * bytestreams_.at( i )->outputAvailable() ) );
}
}
#ifdef E57_MAX_VERBOSE
for ( unsigned i = 0; i < bytestreams_.size(); i++ )
{
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 ( totalByteCount > packetMaxPayloadBytes )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "totalByteCount=" + toString( totalByteCount ) +
" packetMaxPayloadBytes=" + toString( packetMaxPayloadBytes ) );
}
#endif
/// 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
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
dataPacket_.header.reset();
/// 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; //???
#endif
for ( unsigned i = 0; i < bytestreams_.size(); 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; //???
#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; //???
#endif
/// Write contents of each bytestream in dataPacket_
for ( size_t i = 0; i < bytestreams_.size(); 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 ( &p[n] > &packet[DATA_PACKET_MAX] )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "n=" + toString( n ) );
}
#endif
/// Read from encoder output into packet
bytestreams_.at( i )->outputRead( p, n );
/// 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
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 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetLength=" + toString( packetLength ) + " bytestreamSize=" +
toString( bytestreams_.size() * sizeof( uint16_t ) ) +
" totalByteCount=" + toString( totalByteCount ) );
}
#endif
/// 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>
if ( p >= &packet[DATA_PACKET_MAX - 1] )
{
throw E57_EXCEPTION1( E57_ERROR_INTERNAL );
}
*p++ = 0;
packetLength++;
#ifdef E57_MAX_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
/// Double check that data packet is well formed
dataPacket_.verify( packetLength );
/// 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
// 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 ( dataPacketsCount_ == 0 )
{
dataPhysicalOffset_ = packetPhysicalOffset;
}
dataPacketsCount_++;
///!!! update seekIndex here? if started new chunk?
/// Return physical offset of data packet for potential use in seekIndex
return ( packetPhysicalOffset ); //??? needed
}
void CompressedVectorWriterImpl::flush()
{
for ( auto &bytestream : bytestreams_ )
{
bytestream->registerFlushToOutput();
}
}
void CompressedVectorWriterImpl::checkImageFileOpen( const char *srcFileName, int srcLineNumber,
const char *srcFunctionName ) const
{
// unimplemented...
(void)srcFileName; (void)srcLineNumber; (void)srcFunctionName;
}
void CompressedVectorWriterImpl::checkWriterOpen( const char *srcFileName, int srcLineNumber,
const char *srcFunctionName ) const
{
if ( !isOpen_ )
{
throw E57Exception( E57_ERROR_WRITER_NOT_OPEN,
"imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName(),
srcFileName, srcLineNumber, srcFunctionName );
}
}
#ifdef E57_DEBUG
void CompressedVectorWriterImpl::dump( int indent, std::ostream &os )
{
os << space( indent ) << "isOpen:" << isOpen_ << std::endl;
for ( unsigned i = 0; i < sbufs_.size(); i++ )
{
os << space( indent ) << "sbufs[" << i << "]:" << std::endl;
sbufs_.at( i ).dump( indent + 4, os );
}
os << space( indent ) << "cVector:" << std::endl;
cVector_->dump( indent + 4, os );
os << space( indent ) << "proto:" << std::endl;
proto_->dump( indent + 4, os );
for ( unsigned i = 0; i < bytestreams_.size(); i++ )
{
os << space( indent ) << "bytestreams[" << i << "]:" << std::endl;
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.
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 ) << "more unprinted..." << 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 ) << "recordCount: " << recordCount_ << std::endl;
os << space( indent ) << "dataPacketsCount: " << dataPacketsCount_ << std::endl;
os << space( indent ) << "indexPacketsCount: " << indexPacketsCount_ << std::endl;
}
#endif
}

View File

@@ -1,76 +0,0 @@
#pragma once
/*
* 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.
*/
#include "Encoder.h"
#include "Packet.h"
namespace e57
{
class CompressedVectorWriterImpl
{
public:
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 );
bool isOpen() const;
std::shared_ptr<CompressedVectorNodeImpl> compressedVectorNode() const;
void close();
#ifdef E57_DEBUG
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 setBuffers( std::vector<SourceDestBuffer> &sbufs ); //???needed?
size_t totalOutputAvailable() const;
size_t currentPacketSize() const;
uint64_t packetWrite();
void flush();
//??? no default ctor, copy, assignment?
std::vector<SourceDestBuffer> sbufs_;
std::shared_ptr<CompressedVectorNodeImpl> cVector_;
NodeImplSharedPtr proto_;
std::vector<std::shared_ptr<Encoder>> bytestreams_;
DataPacket dataPacket_;
bool isOpen_;
uint64_t sectionHeaderLogicalStart_; /// start of CompressedVector binary section
uint64_t sectionLogicalLength_; /// total length of CompressedVector binary section
uint64_t dataPhysicalOffset_; /// start of first data packet
uint64_t topIndexPhysicalOffset_; /// top level index packet
uint64_t recordCount_; /// number of records written so far
uint64_t dataPacketsCount_; /// number of data packets written so far
uint64_t indexPacketsCount_; /// number of index packets written so far
};
}

View File

@@ -1,88 +0,0 @@
/*
* 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.
*/
#include "DecodeChannel.h"
#include "SourceDestBufferImpl.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 )
{
maxRecordCount = maxRecordCount_arg;
currentPacketLogicalOffset = 0;
currentBytestreamBufferIndex = 0;
currentBytestreamBufferLength = 0;
inputFinished = false;
}
bool DecodeChannel::isOutputBlocked() const
{
/// 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
return ( dbuf.impl()->nextIndex() == dbuf.impl()->capacity() );
}
bool DecodeChannel::isInputBlocked() const
{
/// 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.
return ( currentBytestreamBufferIndex == currentBytestreamBufferLength );
}
#ifdef E57_DEBUG
void DecodeChannel::dump( int indent, std::ostream &os )
{
os << space( indent ) << "dbuf" << std::endl;
dbuf.dump( indent + 4, os );
os << space( indent ) << "decoder:" << std::endl;
decoder->dump( indent + 4, os );
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 ) << "inputFinished: " << inputFinished << std::endl;
os << space( indent ) << "isInputBlocked(): " << isInputBlocked() << std::endl;
os << space( indent ) << "isOutputBlocked(): " << isOutputBlocked() << std::endl;
}
#endif
}

View File

@@ -1,55 +0,0 @@
#pragma once
/*
* 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.
*/
#include "Decoder.h"
namespace e57
{
class SourceDestBuffer;
struct DecodeChannel
{
SourceDestBuffer dbuf; //??? for now, one input per channel
std::shared_ptr<Decoder> decoder;
unsigned bytestreamNumber;
uint64_t maxRecordCount;
uint64_t currentPacketLogicalOffset;
size_t currentBytestreamBufferIndex;
size_t currentBytestreamBufferLength;
bool inputFinished;
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 );
#endif
};
}

View File

@@ -1,892 +0,0 @@
/*
* 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.
*/
#include <algorithm>
#include <cstring>
#include "CompressedVectorNodeImpl.h"
#include "Decoder.h"
#include "FloatNodeImpl.h"
#include "ImageFileImpl.h"
#include "IntegerNodeImpl.h"
#include "ScaledIntegerNodeImpl.h"
#include "SourceDestBufferImpl.h"
using namespace e57;
std::shared_ptr<Decoder> Decoder::DecoderFactory( unsigned bytestreamNumber, //!!! name ok?
const CompressedVectorNodeImpl *cVector,
std::vector<SourceDestBuffer> &dbufs, const ustring & /*codecPath*/ )
{
//!!! verify single dbuf
/// Get node we are going to decode from the CompressedVector's prototype
NodeImplSharedPtr prototype = cVector->getPrototype();
ustring path = dbufs.at( 0 ).pathName();
NodeImplSharedPtr decodeNode = prototype->get( path );
#ifdef E57_MAX_VERBOSE
std::cout << "Node to decode:" << std::endl; //???
decodeNode->dump( 2 );
#endif
uint64_t maxRecordCount = cVector->childCount();
switch ( decodeNode->type() )
{
case E57_INTEGER:
{
std::shared_ptr<IntegerNodeImpl> ini =
std::static_pointer_cast<IntegerNodeImpl>( decodeNode ); // downcast to correct type
/// Get pointer to parent ImageFileImpl, to call bitsNeeded()
ImageFileImplSharedPtr imf( decodeNode->destImageFile_ ); //??? should be function for this,
// imf->parentFile()
//--> ImageFile?
unsigned bitsPerRecord = imf->bitsNeeded( ini->minimum(), ini->maximum() );
//!!! need to pick smarter channel buffer sizes, here and elsewhere
/// Constuct Integer decoder with appropriate register size, based on
/// number of bits stored.
if ( bitsPerRecord == 0 )
{
std::shared_ptr<Decoder> decoder( new ConstantIntegerDecoder( false, bytestreamNumber, dbufs.at( 0 ),
ini->minimum(), 1.0, 0.0, maxRecordCount ) );
return decoder;
}
if ( bitsPerRecord <= 8 )
{
std::shared_ptr<Decoder> decoder( new BitpackIntegerDecoder<uint8_t>(
false, bytestreamNumber, dbufs.at( 0 ), ini->minimum(), ini->maximum(), 1.0, 0.0, maxRecordCount ) );
return decoder;
}
if ( bitsPerRecord <= 16 )
{
std::shared_ptr<Decoder> decoder( new BitpackIntegerDecoder<uint16_t>(
false, bytestreamNumber, dbufs.at( 0 ), ini->minimum(), ini->maximum(), 1.0, 0.0, maxRecordCount ) );
return decoder;
}
if ( bitsPerRecord <= 32 )
{
std::shared_ptr<Decoder> decoder( new BitpackIntegerDecoder<uint32_t>(
false, bytestreamNumber, dbufs.at( 0 ), ini->minimum(), ini->maximum(), 1.0, 0.0, maxRecordCount ) );
return decoder;
}
std::shared_ptr<Decoder> decoder( new BitpackIntegerDecoder<uint64_t>(
false, bytestreamNumber, dbufs.at( 0 ), ini->minimum(), ini->maximum(), 1.0, 0.0, maxRecordCount ) );
return decoder;
}
case E57_SCALED_INTEGER:
{
std::shared_ptr<ScaledIntegerNodeImpl> sini =
std::static_pointer_cast<ScaledIntegerNodeImpl>( decodeNode ); // downcast to correct type
/// Get pointer to parent ImageFileImpl, to call bitsNeeded()
ImageFileImplSharedPtr imf( decodeNode->destImageFile_ ); //??? should be function for this,
// imf->parentFile()
//--> ImageFile?
unsigned bitsPerRecord = imf->bitsNeeded( sini->minimum(), sini->maximum() );
//!!! need to pick smarter channel buffer sizes, here and elsewhere
/// Construct ScaledInteger dencoder with appropriate register size,
/// based on number of bits stored.
if ( bitsPerRecord == 0 )
{
std::shared_ptr<Decoder> decoder( new ConstantIntegerDecoder( true, bytestreamNumber, dbufs.at( 0 ),
sini->minimum(), sini->scale(),
sini->offset(), maxRecordCount ) );
return decoder;
}
if ( bitsPerRecord <= 8 )
{
std::shared_ptr<Decoder> decoder(
new BitpackIntegerDecoder<uint8_t>( true, bytestreamNumber, dbufs.at( 0 ), sini->minimum(),
sini->maximum(), sini->scale(), sini->offset(), maxRecordCount ) );
return decoder;
}
if ( bitsPerRecord <= 16 )
{
std::shared_ptr<Decoder> decoder(
new BitpackIntegerDecoder<uint16_t>( true, bytestreamNumber, dbufs.at( 0 ), sini->minimum(),
sini->maximum(), sini->scale(), sini->offset(), maxRecordCount ) );
return decoder;
}
if ( bitsPerRecord <= 32 )
{
std::shared_ptr<Decoder> decoder(
new BitpackIntegerDecoder<uint32_t>( true, bytestreamNumber, dbufs.at( 0 ), sini->minimum(),
sini->maximum(), sini->scale(), sini->offset(), maxRecordCount ) );
return decoder;
}
std::shared_ptr<Decoder> decoder(
new BitpackIntegerDecoder<uint64_t>( true, bytestreamNumber, dbufs.at( 0 ), sini->minimum(),
sini->maximum(), sini->scale(), sini->offset(), maxRecordCount ) );
return decoder;
}
case E57_FLOAT:
{
std::shared_ptr<FloatNodeImpl> fni =
std::static_pointer_cast<FloatNodeImpl>( decodeNode ); // downcast to correct type
std::shared_ptr<Decoder> decoder(
new BitpackFloatDecoder( bytestreamNumber, dbufs.at( 0 ), fni->precision(), maxRecordCount ) );
return decoder;
}
case E57_STRING:
{
std::shared_ptr<Decoder> decoder(
new BitpackStringDecoder( bytestreamNumber, dbufs.at( 0 ), maxRecordCount ) );
return decoder;
}
default:
{
throw E57_EXCEPTION2( E57_ERROR_BAD_PROTOTYPE, "nodeType=" + toString( decodeNode->type() ) );
}
}
}
Decoder::Decoder( unsigned bytestreamNumber ) : bytestreamNumber_( bytestreamNumber )
{
}
BitpackDecoder::BitpackDecoder( unsigned bytestreamNumber, SourceDestBuffer &dbuf, unsigned alignmentSize,
uint64_t maxRecordCount ) :
Decoder( bytestreamNumber ),
maxRecordCount_( maxRecordCount ), destBuffer_( dbuf.impl() ),
inBuffer_( 1024 ), //!!! need to pick smarter channel buffer sizes
inBufferAlignmentSize_( alignmentSize ), bitsPerWord_( 8 * alignmentSize ), bytesPerWord_( alignmentSize )
{
}
void BitpackDecoder::destBufferSetNew( std::vector<SourceDestBuffer> &dbufs )
{
if ( dbufs.size() != 1 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "dbufsSize=" + toString( dbufs.size() ) );
}
destBuffer_ = dbufs.at( 0 ).impl();
}
size_t BitpackDecoder::inputProcess( const char *source, const size_t availableByteCount )
{
#ifdef E57_MAX_VERBOSE
std::cout << "BitpackDecoder::inputprocess() called, source=" << ( source ? source : "none" )
<< " availableByteCount=" << availableByteCount << std::endl;
#endif
size_t bytesUnsaved = availableByteCount;
size_t bitsEaten = 0;
do
{
size_t byteCount = std::min( bytesUnsaved, inBuffer_.size() - static_cast<size_t>( inBufferEndByte_ ) );
/// Copy input bytes from caller, if any
if ( ( byteCount > 0 ) && source )
{
memcpy( &inBuffer_[inBufferEndByte_], source, byteCount );
/// Advance tail pointer.
inBufferEndByte_ += byteCount;
/// Update amount available from caller
bytesUnsaved -= byteCount;
source += byteCount;
}
#ifdef E57_MAX_VERBOSE
{
unsigned i;
unsigned firstByte = inBufferFirstBit_ / 8;
for ( i = 0; i < byteCount && i < 20; i++ )
{
std::cout << " inBuffer[" << firstByte + i << "]=" << (unsigned)(unsigned char)( inBuffer_[firstByte + i] )
<< std::endl;
}
if ( i < byteCount )
{
std::cout << " " << byteCount - i << "source bytes unprinted..." << std::endl;
}
}
#endif
/// ??? fix doc for new bit interface
/// Now that we have input stored in an aligned buffer, call derived class
/// to try to eat some Note that end of filled buffer may not be at a
/// natural boundary. The subclass may transfer this partial word in a
/// full word transfer, but it must be done carefully to only use the defined
/// bits. inBuffer_ is a multiple of largest word size, so this full word
/// transfer off the end will always be in defined memory.
size_t firstWord = inBufferFirstBit_ / bitsPerWord_;
size_t firstNaturalBit = firstWord * bitsPerWord_;
size_t endBit = inBufferEndByte_ * 8;
#ifdef E57_MAX_VERBOSE
std::cout << " feeding aligned decoder " << endBit - inBufferFirstBit_ << " bits." << std::endl;
#endif
bitsEaten = inputProcessAligned( &inBuffer_[firstWord * bytesPerWord_], inBufferFirstBit_ - firstNaturalBit,
endBit - firstNaturalBit );
#ifdef E57_MAX_VERBOSE
std::cout << " bitsEaten=" << bitsEaten << " firstWord=" << firstWord << " firstNaturalBit=" << firstNaturalBit
<< " endBit=" << endBit << std::endl;
#endif
#ifdef E57_DEBUG
if ( bitsEaten > endBit - inBufferFirstBit_ )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "bitsEaten=" + toString( bitsEaten ) +
" endBit=" + toString( endBit ) +
" inBufferFirstBit=" + toString( inBufferFirstBit_ ) );
}
#endif
inBufferFirstBit_ += bitsEaten;
/// Shift uneaten data to beginning of inBuffer_, keep on natural word
/// boundaries.
inBufferShiftDown();
/// If the lower level processing didn't eat anything on this iteration,
/// stop looping and tell caller how much we ate or stored.
} while ( bytesUnsaved > 0 && bitsEaten > 0 );
/// Return the number of bytes we ate/saved.
return ( availableByteCount - bytesUnsaved );
}
void BitpackDecoder::stateReset()
{
inBufferFirstBit_ = 0;
inBufferEndByte_ = 0;
}
void BitpackDecoder::inBufferShiftDown()
{
/// Move uneaten data down to beginning of inBuffer_.
/// Keep on natural boundaries.
/// Moves all of word that contains inBufferFirstBit.
size_t firstWord = inBufferFirstBit_ / bitsPerWord_;
size_t firstNaturalByte = firstWord * bytesPerWord_;
#ifdef E57_DEBUG
if ( firstNaturalByte > inBufferEndByte_ )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "firstNaturalByte=" + toString( firstNaturalByte ) +
" inBufferEndByte=" + toString( inBufferEndByte_ ) );
}
#endif
size_t byteCount = inBufferEndByte_ - firstNaturalByte;
if ( byteCount > 0 )
{
memmove( &inBuffer_[0], &inBuffer_[firstNaturalByte],
byteCount ); /// Overlapping regions ok with memmove().
}
/// Update indexes
inBufferEndByte_ = byteCount;
inBufferFirstBit_ = inBufferFirstBit_ % bitsPerWord_;
}
#ifdef E57_DEBUG
void BitpackDecoder::dump( int indent, std::ostream &os )
{
os << space( indent ) << "bytestreamNumber: " << bytestreamNumber_ << std::endl;
os << space( indent ) << "currentRecordIndex: " << currentRecordIndex_ << std::endl;
os << space( indent ) << "maxRecordCount: " << maxRecordCount_ << std::endl;
os << space( indent ) << "destBuffer:" << std::endl;
destBuffer_->dump( indent + 4, os );
os << space( indent ) << "inBufferFirstBit: " << inBufferFirstBit_ << std::endl;
os << space( indent ) << "inBufferEndByte: " << inBufferEndByte_ << std::endl;
os << space( indent ) << "inBufferAlignmentSize: " << inBufferAlignmentSize_ << std::endl;
os << space( indent ) << "bitsPerWord: " << bitsPerWord_ << std::endl;
os << space( indent ) << "bytesPerWord: " << bytesPerWord_ << std::endl;
os << space( indent ) << "inBuffer:" << std::endl;
unsigned i;
for ( i = 0; i < inBuffer_.size() && i < 20; i++ )
{
os << space( indent + 4 ) << "inBuffer[" << i
<< "]: " << static_cast<unsigned>( static_cast<unsigned char>( inBuffer_.at( i ) ) ) << std::endl;
}
if ( i < inBuffer_.size() )
{
os << space( indent + 4 ) << inBuffer_.size() - i << " more unprinted..." << std::endl;
}
}
#endif
//================================================================
BitpackFloatDecoder::BitpackFloatDecoder( unsigned bytestreamNumber, SourceDestBuffer &dbuf, FloatPrecision precision,
uint64_t maxRecordCount ) :
BitpackDecoder( bytestreamNumber, dbuf, ( precision == E57_SINGLE ) ? sizeof( float ) : sizeof( double ),
maxRecordCount ),
precision_( precision )
{
}
size_t BitpackFloatDecoder::inputProcessAligned( const char *inbuf, const size_t firstBit, const size_t endBit )
{
#ifdef E57_MAX_VERBOSE
std::cout << "BitpackFloatDecoder::inputProcessAligned() called, inbuf=" << inbuf << " firstBit=" << firstBit
<< " endBit=" << endBit << std::endl;
#endif
/// Read from inbuf, decode, store in destBuffer
/// Repeat until have filled destBuffer, or completed all records
size_t n = destBuffer_->capacity() - destBuffer_->nextIndex();
size_t typeSize = ( precision_ == E57_SINGLE ) ? sizeof( float ) : sizeof( double );
#ifdef E57_DEBUG
#if 0 // I know no way to do this portably <rs>
// Deactivate for now until a better solution is found.
/// Verify that inbuf is naturally aligned to correct boundary (4 or 8 bytes). Base class should be doing this for us.
if (reinterpret_cast<unsigned>(inbuf) % typeSize) {
throw E57_EXCEPTION2(E57_ERROR_INTERNAL,
"inbuf=" + toString(reinterpret_cast<unsigned>(inbuf))
+ " typeSize=" + toString(typeSize));
}
#endif
/// Verify first bit is zero
if ( firstBit != 0 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "firstBit=" + toString( firstBit ) );
}
#endif
/// Calc how many whole records worth of data we have in inbuf
size_t maxInputRecords = ( endBit - firstBit ) / ( 8 * typeSize );
/// Can't process more records than we have input data for.
if ( n > maxInputRecords )
{
n = maxInputRecords;
}
// Can't process more than defined in input file
if ( n > maxRecordCount_ - currentRecordIndex_ )
{
n = static_cast<unsigned>( maxRecordCount_ - currentRecordIndex_ );
}
#ifdef E57_MAX_VERBOSE
std::cout << " n:" << n << std::endl; //???
#endif
if ( precision_ == E57_SINGLE )
{
/// Form the starting address for first data location in inBuffer
auto inp = reinterpret_cast<const float *>( inbuf );
/// Copy floats from inbuf to destBuffer_
for ( unsigned i = 0; i < n; i++ )
{
float value = *inp;
#ifdef E57_MAX_VERBOSE
std::cout << " got float value=" << value << std::endl;
#endif
destBuffer_->setNextFloat( value );
inp++;
}
}
else
{ /// E57_DOUBLE precision
/// Form the starting address for first data location in inBuffer
auto inp = reinterpret_cast<const double *>( inbuf );
/// Copy doubles from inbuf to destBuffer_
for ( unsigned i = 0; i < n; i++ )
{
double value = *inp;
#ifdef E57_MAX_VERBOSE
std::cout << " got double value=" << value << std::endl;
#endif
destBuffer_->setNextDouble( value );
inp++;
}
}
/// Update counts of records processed
currentRecordIndex_ += n;
/// Returned number of bits processed (always a multiple of alignment size).
return ( n * 8 * typeSize );
}
#ifdef E57_DEBUG
void BitpackFloatDecoder::dump( int indent, std::ostream &os )
{
BitpackDecoder::dump( indent, os );
if ( precision_ == E57_SINGLE )
{
os << space( indent ) << "precision: E57_SINGLE" << std::endl;
}
else
{
os << space( indent ) << "precision: E57_DOUBLE" << std::endl;
}
}
#endif
//================================================================
BitpackStringDecoder::BitpackStringDecoder( unsigned bytestreamNumber, SourceDestBuffer &dbuf,
uint64_t maxRecordCount ) :
BitpackDecoder( bytestreamNumber, dbuf, sizeof( char ), maxRecordCount )
{
}
size_t BitpackStringDecoder::inputProcessAligned( const char *inbuf, const size_t firstBit, const size_t endBit )
{
#ifdef E57_MAX_VERBOSE
std::cout << "BitpackStringDecoder::inputProcessAligned() called, inbuf=" << inbuf << " firstBit=" << firstBit
<< " endBit=" << endBit << std::endl;
#endif
/// Read from inbuf, decode, store in destBuffer
/// Repeat until have filled destBuffer, or completed all records
#ifdef E57_DEBUG
/// Verify first bit is zero (always byte-aligned)
if ( firstBit != 0 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "firstBit=" + toString( firstBit ) );
}
#endif
/// Converts start/end bits to whole bytes
size_t nBytesAvailable = ( endBit - firstBit ) >> 3;
size_t nBytesRead = 0;
/// Loop until we've finished all the records, or ran out of input currently
/// available
while ( currentRecordIndex_ < maxRecordCount_ && nBytesRead < nBytesAvailable )
{
#ifdef E57_MAX_VERBOSE
std::cout << "read string loop1: readingPrefix=" << readingPrefix_ << " prefixLength=" << prefixLength_
<< " nBytesPrefixRead=" << nBytesPrefixRead_ << " nBytesStringRead=" << nBytesStringRead_ << std::endl;
#endif
if ( readingPrefix_ )
{
/// Try to read more prefix bytes
while ( nBytesRead < nBytesAvailable && ( nBytesPrefixRead_ == 0 || nBytesPrefixRead_ < prefixLength_ ) )
{
/// If first byte of prefix, test the least significant bit to see
/// how long prefix is
if ( nBytesPrefixRead_ == 0 )
{
if ( *inbuf & 0x01 )
{
prefixLength_ = 8; // 8 byte prefix, length up to 2^63-1
}
else
{
prefixLength_ = 1; // 1 byte prefix, length up to 2^7-1
}
}
/// Accumulate prefix bytes
prefixBytes_[nBytesPrefixRead_] = *inbuf++;
nBytesPrefixRead_++;
nBytesRead++;
}
#ifdef E57_MAX_VERBOSE
std::cout << "read string loop2: readingPrefix=" << readingPrefix_ << " prefixLength=" << prefixLength_
<< " nBytesPrefixRead=" << nBytesPrefixRead_ << " nBytesStringRead=" << nBytesStringRead_
<< std::endl;
#endif
/// If got all of prefix, convert to length and get ready to read
/// string
if ( nBytesPrefixRead_ > 0 && nBytesPrefixRead_ == prefixLength_ )
{
if ( prefixLength_ == 1 )
{
/// Single byte prefix, extract length from b7-b1.
/// Removing the least significant bit (which says this is a
/// short prefix).
stringLength_ = static_cast<uint64_t>( prefixBytes_[0] >> 1 );
}
else
{
/// Eight byte prefix, extract length from b63-b1. Little endian
/// ordering. Removing the least significant bit (which says this
/// is a long prefix).
stringLength_ = ( static_cast<uint64_t>( prefixBytes_[0] ) >> 1 ) +
( static_cast<uint64_t>( prefixBytes_[1] ) << ( 1 * 8 - 1 ) ) +
( static_cast<uint64_t>( prefixBytes_[2] ) << ( 2 * 8 - 1 ) ) +
( static_cast<uint64_t>( prefixBytes_[3] ) << ( 3 * 8 - 1 ) ) +
( static_cast<uint64_t>( prefixBytes_[4] ) << ( 4 * 8 - 1 ) ) +
( static_cast<uint64_t>( prefixBytes_[5] ) << ( 5 * 8 - 1 ) ) +
( static_cast<uint64_t>( prefixBytes_[6] ) << ( 6 * 8 - 1 ) ) +
( static_cast<uint64_t>( prefixBytes_[7] ) << ( 7 * 8 - 1 ) );
}
/// Get ready to read string contents
readingPrefix_ = false;
prefixLength_ = 1;
memset( prefixBytes_, 0, sizeof( prefixBytes_ ) );
nBytesPrefixRead_ = 0;
currentString_ = "";
nBytesStringRead_ = 0;
}
#ifdef E57_MAX_VERBOSE
std::cout << "read string loop3: readingPrefix=" << readingPrefix_ << " prefixLength=" << prefixLength_
<< " nBytesPrefixRead=" << nBytesPrefixRead_ << " nBytesStringRead=" << nBytesStringRead_
<< std::endl;
#endif
}
/// If currently reading string contents, keep doing it until have
/// complete string
if ( !readingPrefix_ )
{
/// Calc how many bytes we need to complete current string
uint64_t nBytesNeeded = stringLength_ - nBytesStringRead_;
/// Can process the smaller of unread or needed bytes
size_t nBytesProcess = nBytesAvailable - nBytesRead;
if ( nBytesNeeded < static_cast<uint64_t>( nBytesProcess ) )
{
nBytesProcess = static_cast<unsigned>( nBytesNeeded );
}
/// Append to current string and update counts
currentString_ += ustring( inbuf, nBytesProcess );
inbuf += nBytesProcess;
nBytesRead += nBytesProcess;
nBytesStringRead_ += nBytesProcess;
/// Check if completed reading the string contents
if ( nBytesStringRead_ == stringLength_ )
{
/// Save accumulated string to dest buffer
destBuffer_->setNextString( currentString_ );
currentRecordIndex_++;
/// Get ready to read next prefix
readingPrefix_ = true;
prefixLength_ = 1;
memset( prefixBytes_, 0, sizeof( prefixBytes_ ) );
nBytesPrefixRead_ = 0;
stringLength_ = 0;
currentString_ = "";
nBytesStringRead_ = 0;
}
}
}
/// Returned number of bits processed (always a multiple of alignment size).
return ( nBytesRead * 8 );
}
#ifdef E57_DEBUG
void BitpackStringDecoder::dump( int indent, std::ostream &os )
{
BitpackDecoder::dump( indent, os );
os << space( indent ) << "readingPrefix: " << readingPrefix_ << std::endl;
os << space( indent ) << "prefixLength: " << prefixLength_ << std::endl;
os << space( indent ) << "prefixBytes[8]: " << static_cast<unsigned>( prefixBytes_[0] ) << " "
<< static_cast<unsigned>( prefixBytes_[1] ) << " " << static_cast<unsigned>( prefixBytes_[2] ) << " "
<< static_cast<unsigned>( prefixBytes_[3] ) << " " << static_cast<unsigned>( prefixBytes_[4] ) << " "
<< static_cast<unsigned>( prefixBytes_[5] ) << " " << static_cast<unsigned>( prefixBytes_[6] ) << " "
<< static_cast<unsigned>( prefixBytes_[7] ) << std::endl;
os << space( indent ) << "nBytesPrefixRead: " << nBytesPrefixRead_ << std::endl;
os << space( indent ) << "stringLength: " << stringLength_ << std::endl;
os << space( indent )
<< "currentString: "
""
<< currentString_
<< ""
""
<< std::endl;
os << space( indent ) << "nBytesStringRead: " << nBytesStringRead_ << std::endl;
}
#endif
//================================================================
template <typename RegisterT>
BitpackIntegerDecoder<RegisterT>::BitpackIntegerDecoder( bool isScaledInteger, unsigned bytestreamNumber,
SourceDestBuffer &dbuf, int64_t minimum, int64_t maximum,
double scale, double offset, uint64_t maxRecordCount ) :
BitpackDecoder( bytestreamNumber, dbuf, sizeof( RegisterT ), maxRecordCount ),
isScaledInteger_( isScaledInteger ), minimum_( minimum ), maximum_( maximum ), scale_( scale ), offset_( offset )
{
/// Get pointer to parent ImageFileImpl
ImageFileImplSharedPtr imf( dbuf.impl()->destImageFile() ); //??? should be function for this,
// imf->parentFile() --> ImageFile?
bitsPerRecord_ = imf->bitsNeeded( minimum_, maximum_ );
destBitMask_ = ( bitsPerRecord_ == 64 ) ? ~0 : static_cast<RegisterT>( 1ULL << bitsPerRecord_ ) - 1;
}
template <typename RegisterT>
size_t BitpackIntegerDecoder<RegisterT>::inputProcessAligned( const char *inbuf, const size_t firstBit,
const size_t endBit )
{
#ifdef E57_MAX_VERBOSE
std::cout << "BitpackIntegerDecoder::inputProcessAligned() called, inbuf=" << (void *)( inbuf )
<< " firstBit=" << firstBit << " endBit=" << endBit << std::endl;
#endif
/// Read from inbuf, decode, store in destBuffer
/// Repeat until have filled destBuffer, or completed all records
#ifdef E57_DEBUG
#if 0 // I know now way to do this portably
// Deactivate for now until a better solution is found.
/// Verify that inbuf is naturally aligned to RegisterT boundary (1, 2, 4,or 8 bytes). Base class is doing this for us.
if ((reinterpret_cast<unsigned>(inbuf)) % sizeof(RegisterT))
throw E57_EXCEPTION2(E57_ERROR_INTERNAL, "inbuf=" + toString(reinterpret_cast<unsigned>(inbuf)));
#endif
/// Verfiy first bit is in first word
if ( firstBit >= 8 * sizeof( RegisterT ) )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "firstBit=" + toString( firstBit ) );
}
#endif
size_t destRecords = destBuffer_->capacity() - destBuffer_->nextIndex();
/// Precalculate exact number of full records that are in inbuf
/// We can handle the case where don't have a full word at end of inbuf, but
/// all the bits of the record are there;
size_t bitCount = endBit - firstBit;
size_t maxInputRecords = bitCount / bitsPerRecord_;
/// Number of transfers is the smaller of what was requested and what is
/// available in input.
size_t recordCount = std::min( destRecords, maxInputRecords );
// Can't process more than defined in input file
if ( static_cast<uint64_t>( recordCount ) > maxRecordCount_ - currentRecordIndex_ )
{
recordCount = static_cast<unsigned>( maxRecordCount_ - currentRecordIndex_ );
}
#ifdef E57_MAX_VERBOSE
std::cout << " recordCount=" << recordCount << std::endl;
#endif
auto inp = reinterpret_cast<const RegisterT *>( inbuf );
unsigned wordPosition = 0; /// The index in inbuf of the word we are currently working on.
/// For example on little endian machine:
/// Assume: registerT=uint32_t, bitOffset=20, destBitMask=0x00007fff (for a
/// 15 bit value). inp[wordPosition] LLLLLLLL LLLLXXXX
/// XXXXXXXX XXXXXXXX Note LSB of value is at bit20 inp(wordPosition+1]
/// XXXXXXXX XXXXXXXX XXXXXXXX XXXXXHHH H=high bits of value,
/// X=uninteresting bits low = inp[i] >> bitOffset 00000000
/// 00000000 0000LLLL LLLLLLLL L=low bits of value, X=uninteresting bits
/// high = inp[i+1] << (32-bitOffset) XXXXXXXX XXXXXXXX XHHH0000 00000000
/// w = high | low XXXXXXXX XXXXXXXX XHHHLLLL LLLLLLLL destBitmask 00000000
/// 00000000 01111111 11111111 w & mask 00000000
/// 00000000 0HHHLLLL LLLLLLLL
size_t bitOffset = firstBit;
for ( size_t i = 0; i < recordCount; i++ )
{
/// Get lower word (contains at least the LSbit of the value),
RegisterT low = inp[wordPosition];
#ifdef E57_MAX_VERBOSE
std::cout << " bitOffset: " << bitOffset << std::endl;
std::cout << " low: " << binaryString( low ) << std::endl;
#endif
RegisterT w;
if ( bitOffset > 0 )
{
/// Get upper word (may or may not contain interesting bits),
RegisterT high = inp[wordPosition + 1];
#ifdef E57_MAX_VERBOSE
std::cout << " high:" << binaryString( high ) << std::endl;
#endif
/// Shift high to just above the lower bits, shift low LSBit to bit0,
/// OR together. Note shifts are logical (not arithmetic) because using
/// unsigned variables.
w = ( high << ( 8 * sizeof( RegisterT ) - bitOffset ) ) | ( low >> bitOffset );
}
else
{
/// The left shift (used above) is not defined if shift is >= size of
/// word
w = low;
}
#ifdef E57_MAX_VERBOSE
std::cout << " w: " << binaryString( w ) << std::endl;
#endif
/// Mask off uninteresting bits
w &= destBitMask_;
/// Add minimum_ to value to get back what writer originally sent
int64_t value = minimum_ + static_cast<uint64_t>( w );
#ifdef E57_MAX_VERBOSE
std::cout << " Storing value=" << value << std::endl;
#endif
/// The parameter isScaledInteger_ determines which version of
/// setNextInt64 gets called
if ( isScaledInteger_ )
{
destBuffer_->setNextInt64( value, scale_, offset_ );
}
else
{
destBuffer_->setNextInt64( value );
}
/// Store the result in next available position in the user's dest buffer
/// Calc next bit alignment and which word it starts in
bitOffset += bitsPerRecord_;
if ( bitOffset >= 8 * sizeof( RegisterT ) )
{
bitOffset -= 8 * sizeof( RegisterT );
wordPosition++;
}
#ifdef E57_MAX_VERBOSE
std::cout << " Processed " << i + 1 << " records, wordPosition=" << wordPosition << " decoder:" << std::endl;
dump( 4 );
#endif
}
/// Update counts of records processed
currentRecordIndex_ += recordCount;
/// Return number of bits processed.
return ( recordCount * bitsPerRecord_ );
}
#ifdef E57_DEBUG
template <typename RegisterT> void BitpackIntegerDecoder<RegisterT>::dump( int indent, std::ostream &os )
{
BitpackDecoder::dump( indent, os );
os << space( indent ) << "isScaledInteger: " << isScaledInteger_ << std::endl;
os << space( indent ) << "minimum: " << minimum_ << std::endl;
os << space( indent ) << "maximum: " << maximum_ << std::endl;
os << space( indent ) << "scale: " << scale_ << std::endl;
os << space( indent ) << "offset: " << offset_ << std::endl;
os << space( indent ) << "bitsPerRecord: " << bitsPerRecord_ << std::endl;
os << space( indent ) << "destBitMask: " << binaryString( destBitMask_ ) << " = " << hexString( destBitMask_ )
<< std::endl;
}
#endif
//================================================================
ConstantIntegerDecoder::ConstantIntegerDecoder( bool isScaledInteger, unsigned bytestreamNumber, SourceDestBuffer &dbuf,
int64_t minimum, double scale, double offset,
uint64_t maxRecordCount ) :
Decoder( bytestreamNumber ),
maxRecordCount_( maxRecordCount ), destBuffer_( dbuf.impl() ), isScaledInteger_( isScaledInteger ),
minimum_( minimum ), scale_( scale ), offset_( offset )
{
}
void ConstantIntegerDecoder::destBufferSetNew( std::vector<SourceDestBuffer> &dbufs )
{
if ( dbufs.size() != 1 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "dbufsSize=" + toString( dbufs.size() ) );
}
destBuffer_ = dbufs.at( 0 ).impl();
}
size_t ConstantIntegerDecoder::inputProcess( const char *source, const size_t availableByteCount )
{
(void)source; (void)availableByteCount;
#ifdef E57_MAX_VERBOSE
std::cout << "ConstantIntegerDecoder::inputprocess() called, source=" << (void *)( source )
<< " availableByteCount=" << availableByteCount << std::endl;
#endif
/// We don't need any input bytes to produce output, so ignore source and
/// availableByteCount.
/// Fill dest buffer unless get to maxRecordCount
size_t count = destBuffer_->capacity() - destBuffer_->nextIndex();
uint64_t remainingRecordCount = maxRecordCount_ - currentRecordIndex_;
if ( static_cast<uint64_t>( count ) > remainingRecordCount )
{
count = static_cast<unsigned>( remainingRecordCount );
}
if ( isScaledInteger_ )
{
for ( size_t i = 0; i < count; i++ )
{
destBuffer_->setNextInt64( minimum_, scale_, offset_ );
}
}
else
{
for ( size_t i = 0; i < count; i++ )
{
destBuffer_->setNextInt64( minimum_ );
}
}
currentRecordIndex_ += count;
return ( count );
}
void ConstantIntegerDecoder::stateReset()
{
}
#ifdef E57_DEBUG
void ConstantIntegerDecoder::dump( int indent, std::ostream &os )
{
os << space( indent ) << "bytestreamNumber: " << bytestreamNumber_ << std::endl;
os << space( indent ) << "currentRecordIndex: " << currentRecordIndex_ << std::endl;
os << space( indent ) << "maxRecordCount: " << maxRecordCount_ << std::endl;
os << space( indent ) << "isScaledInteger: " << isScaledInteger_ << std::endl;
os << space( indent ) << "minimum: " << minimum_ << std::endl;
os << space( indent ) << "scale: " << scale_ << std::endl;
os << space( indent ) << "offset: " << offset_ << std::endl;
os << space( indent ) << "destBuffer:" << std::endl;
destBuffer_->dump( indent + 4, os );
}
#endif

View File

@@ -1,180 +0,0 @@
/*
* 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 "Common.h"
namespace e57
{
class Decoder
{
public:
static std::shared_ptr<Decoder> DecoderFactory( unsigned bytestreamNumber,
const CompressedVectorNodeImpl *cVector,
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 void stateReset() = 0;
unsigned bytestreamNumber() const
{
return bytestreamNumber_;
}
#ifdef E57_DEBUG
virtual void dump( int indent = 0, std::ostream &os = std::cout ) = 0;
#endif
protected:
Decoder( unsigned bytestreamNumber );
unsigned int bytestreamNumber_;
};
class BitpackDecoder : public Decoder
{
public:
void destBufferSetNew( std::vector<SourceDestBuffer> &dbufs ) override;
uint64_t totalRecordsCompleted() override
{
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;
void stateReset() override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) override;
#endif
protected:
BitpackDecoder( unsigned bytestreamNumber, SourceDestBuffer &dbuf, unsigned alignmentSize,
uint64_t maxRecordCount );
void inBufferShiftDown();
uint64_t currentRecordIndex_ = 0;
uint64_t maxRecordCount_ = 0;
std::shared_ptr<SourceDestBufferImpl> destBuffer_;
std::vector<char> inBuffer_;
size_t inBufferFirstBit_ = 0;
size_t inBufferEndByte_ = 0;
unsigned int inBufferAlignmentSize_;
unsigned int bitsPerWord_;
unsigned int bytesPerWord_;
};
class BitpackFloatDecoder : public BitpackDecoder
{
public:
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;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) override;
#endif
protected:
FloatPrecision precision_ = E57_SINGLE;
};
class BitpackStringDecoder : public BitpackDecoder
{
public:
BitpackStringDecoder( unsigned bytestreamNumber, SourceDestBuffer &dbuf, uint64_t maxRecordCount );
size_t inputProcessAligned( const char *inbuf, const size_t firstBit, const size_t endBit ) override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) override;
#endif
protected:
bool readingPrefix_ = true;
int prefixLength_ = 1;
uint8_t prefixBytes_[8] = {};
int nBytesPrefixRead_ = 0;
uint64_t stringLength_ = 0;
ustring currentString_;
uint64_t nBytesStringRead_ = 0;
};
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 );
size_t inputProcessAligned( const char *inbuf, const size_t firstBit, const size_t endBit ) override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) override;
#endif
protected:
bool isScaledInteger_;
int64_t minimum_;
int64_t maximum_;
double scale_;
double offset_;
unsigned bitsPerRecord_;
RegisterT destBitMask_;
};
class ConstantIntegerDecoder : public Decoder
{
public:
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;
void stateReset() override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) override;
#endif
protected:
uint64_t currentRecordIndex_ = 0;
uint64_t maxRecordCount_;
std::shared_ptr<SourceDestBufferImpl> destBuffer_;
bool isScaledInteger_;
int64_t minimum_;
double scale_;
double offset_;
};
}

View File

@@ -1,447 +0,0 @@
/*
* 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.
*/
#include "E57Exception.h"
#include "E57Version.h"
namespace e57
{
/*!
@class E57Exception
@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).
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.
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.
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.
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
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>).
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
*/
//! @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;
#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
*/
const char *E57Exception::what() const noexcept
{
return "E57 exception";
}
/*!
@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.
@see E57ExceptionsFunctions.cpp example
*/
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.
*/
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.
*/
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
#ifndef REVISION_ID
#error "Need to specify REVISION_ID on command line"
#endif
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
*/
std::string Utilities::errorCodeToString( ErrorCode ecode )
{
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:
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:
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:
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:
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:
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)";
default:
return "unknown error (" + std::to_string( ecode ) + ")";
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +0,0 @@
// SPDX-License-Identifier: BSL-1.0
// Copyright (c) 2020 PTC Inc.
// 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.
#define _USE_MATH_DEFINES
#include <cmath>
#include "E57SimpleData.h"
namespace e57
{
// To avoid exposing M_PI, we define the constructor here.
SphericalBounds::SphericalBounds()
{
rangeMinimum = 0.;
rangeMaximum = E57_DOUBLE_MAX;
azimuthStart = -M_PI;
azimuthEnd = M_PI;
elevationMinimum = -M_PI / 2.;
elevationMaximum = M_PI / 2.;
}
} // end namespace e57

View File

@@ -1,131 +0,0 @@
/*
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
* Copyright (c) 2020 PTC Inc.
*
* 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.
*/
#include "E57SimpleReader.h"
#include "ReaderImpl.h"
namespace e57
{
Reader::Reader( const ustring &filePath ) : impl_( new ReaderImpl( 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
{
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
{
return impl_->ReadImage2DData( imageIndex, imageProjection, imageType, pBuffer, start, count );
};
int64_t Reader::GetData3DCount() const
{
return impl_->GetData3DCount();
};
ImageFile Reader::GetRawIMF() const
{
return impl_->GetRawIMF();
}
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
{
return impl_->GetData3DSizes( dataIndex, rowMax, columnMax, pointsSize, groupsSize, countSize, bColumnIndex );
}
bool Reader::ReadData3DGroupsData( int64_t dataIndex, int64_t groupCount, int64_t *idElementValue,
int64_t *startPointIndex, int64_t *pointCount ) const
{
return impl_->ReadData3DGroupsData( dataIndex, groupCount, idElementValue, startPointIndex, pointCount );
}
CompressedVectorReader Reader::SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
const Data3DPointsData &buffers ) const
{
return impl_->SetUpData3DPointsData( dataIndex, pointCount, buffers );
}
CompressedVectorReader Reader::SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
const Data3DPointsData_d &buffers ) const
{
return impl_->SetUpData3DPointsData( dataIndex, pointCount, buffers );
}
} // end namespace e57

View File

@@ -1,103 +0,0 @@
/*
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
* Copyright (c) 2020 PTC Inc.
*
* 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.
*/
#include "E57SimpleWriter.h"
#include "WriterImpl.h"
namespace e57
{
Writer::Writer( const ustring &filePath, const ustring &coordinateMetaData ) :
impl_( new WriterImpl( filePath, coordinateMetaData ) )
{
}
bool Writer::IsOpen() const
{
return impl_->IsOpen();
};
bool Writer::Close()
{
return impl_->Close();
};
ImageFile Writer::GetRawIMF()
{
return impl_->GetRawIMF();
}
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

View File

@@ -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;
}

View File

@@ -1,919 +0,0 @@
/*
* 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.
*/
#include <xercesc/sax2/Attributes.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/util/BinInputStream.hpp>
#include <xercesc/util/TransService.hpp>
#include "BlobNodeImpl.h"
#include "CheckedFile.h"
#include "CompressedVectorNodeImpl.h"
#include "E57XmlParser.h"
#include "FloatNodeImpl.h"
#include "ImageFileImpl.h"
#include "IntegerNodeImpl.h"
#include "ScaledIntegerNodeImpl.h"
#include "StringNodeImpl.h"
#include "VectorNodeImpl.h"
#if __GNUC__ >= 11
#include <limits>
#endif
using namespace e57;
using namespace XERCES_CPP_NAMESPACE;
// define convenient constants for the attribute names
static const XMLCh att_minimum[] = {
chLatin_m, chLatin_i, chLatin_n, chLatin_i, chLatin_m, chLatin_u, chLatin_m, chNull
};
static const XMLCh att_maximum[] = {
chLatin_m, chLatin_a, chLatin_x, chLatin_i, chLatin_m, chLatin_u, chLatin_m, chNull
};
static const XMLCh att_scale[] = { chLatin_s, chLatin_c, chLatin_a, chLatin_l, chLatin_e, chNull };
static const XMLCh att_offset[] = { chLatin_o, chLatin_f, chLatin_f, chLatin_s, chLatin_e, chLatin_t, chNull };
static const XMLCh att_precision[] = { chLatin_p, chLatin_r, chLatin_e, chLatin_c, chLatin_i,
chLatin_s, chLatin_i, chLatin_o, chLatin_n, chNull };
static const XMLCh att_allowHeterogeneousChildren[] = {
chLatin_a, chLatin_l, chLatin_l, chLatin_o, chLatin_w, chLatin_H, chLatin_e, chLatin_t, chLatin_e,
chLatin_r, chLatin_o, chLatin_g, chLatin_e, chLatin_n, chLatin_e, chLatin_o, chLatin_u, chLatin_s,
chLatin_C, chLatin_h, chLatin_i, chLatin_l, chLatin_d, chLatin_r, chLatin_e, chLatin_n, chNull
};
static const XMLCh att_fileOffset[] = { chLatin_f, chLatin_i, chLatin_l, chLatin_e, chLatin_O, chLatin_f,
chLatin_f, chLatin_s, chLatin_e, chLatin_t, chNull };
static const XMLCh att_type[] = { chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };
static const XMLCh att_length[] = { chLatin_l, chLatin_e, chLatin_n, chLatin_g, chLatin_t, chLatin_h, chNull };
static const XMLCh att_recordCount[] = { chLatin_r, chLatin_e, chLatin_c, chLatin_o, chLatin_r, chLatin_d,
chLatin_C, chLatin_o, chLatin_u, chLatin_n, chLatin_t, chNull };
inline int64_t convertStrToLL( const std::string &inStr )
{
#if defined( _MSC_VER )
return _atoi64( inStr.c_str() );
#elif defined( __GNUC__ )
return strtoll( inStr.c_str(), nullptr, 10 );
#else
#error "Need to define string to long long conversion for this compiler"
#endif
}
//=============================================================================
// E57FileInputStream
class E57FileInputStream : public BinInputStream
{
public:
E57FileInputStream( CheckedFile *cf, uint64_t logicalStart, uint64_t logicalLength );
~E57FileInputStream() override = default;
E57FileInputStream( const E57FileInputStream & ) = delete;
E57FileInputStream &operator=( const E57FileInputStream & ) = delete;
XMLFilePos curPos() const override
{
return ( logicalPosition_ );
}
XMLSize_t readBytes( XMLByte *const toFill, const XMLSize_t maxToRead ) override;
const XMLCh *getContentType() const override
{
return nullptr;
}
private:
//??? lifetime of cf_ must be longer than this object!
CheckedFile *cf_;
uint64_t logicalStart_;
uint64_t logicalLength_;
uint64_t logicalPosition_;
};
E57FileInputStream::E57FileInputStream( CheckedFile *cf, uint64_t logicalStart, uint64_t logicalLength ) :
cf_( cf ), logicalStart_( logicalStart ), logicalLength_( logicalLength ), logicalPosition_( logicalStart )
{
}
XMLSize_t E57FileInputStream::readBytes( XMLByte *const toFill, const XMLSize_t maxToRead )
{
if ( logicalPosition_ > logicalStart_ + logicalLength_ )
{
return ( 0 );
}
int64_t available = logicalStart_ + logicalLength_ - logicalPosition_;
if ( available <= 0 )
{
return ( 0 );
}
/// size_t and XMLSize_t should be compatible, should get compiler warning
/// here if not
size_t maxToRead_size = maxToRead;
/// Be careful if size_t is smaller than int64_t
size_t available_size;
if ( sizeof( size_t ) >= sizeof( int64_t ) )
{
/// size_t is at least as big as int64_t
available_size = static_cast<size_t>( available );
}
else
{
/// size_t is smaller than int64_t, Calc max that size_t can hold
const int64_t size_max = std::numeric_limits<size_t>::max();
/// read smaller of size_max, available
///??? redo
if ( size_max < available )
{
available_size = static_cast<size_t>( size_max );
}
else
{
available_size = static_cast<size_t>( available );
}
}
size_t readCount = std::min( maxToRead_size, available_size );
cf_->seek( logicalPosition_ );
cf_->read( reinterpret_cast<char *>( toFill ), readCount ); //??? cast ok?
logicalPosition_ += readCount;
return ( readCount );
}
//=============================================================================
// E57XmlFileInputSource
E57XmlFileInputSource::E57XmlFileInputSource( CheckedFile *cf, uint64_t logicalStart, uint64_t logicalLength ) :
InputSource( "E57File",
XMLPlatformUtils::fgMemoryManager ), //??? what if want to use our own
// memory
// manager?, what bufid is good?
cf_( cf ), logicalStart_( logicalStart ), logicalLength_( logicalLength )
{
}
BinInputStream *E57XmlFileInputSource::makeStream() const
{
return new E57FileInputStream( cf_, logicalStart_, logicalLength_ );
}
//=============================================================================
// E57XmlParser::ParseInfo
E57XmlParser::ParseInfo::ParseInfo() :
nodeType( static_cast<NodeType>( 0 ) ), minimum( 0 ), maximum( 0 ), scale( 0 ), offset( 0 ),
precision( static_cast<FloatPrecision>( 0 ) ), floatMinimum( 0 ), floatMaximum( 0 ), fileOffset( 0 ), length( 0 ),
allowHeterogeneousChildren( false ), recordCount( 0 )
{
}
void E57XmlParser::ParseInfo::dump( int indent, std::ostream &os ) const
{
os << space( indent ) << "nodeType: " << nodeType << std::endl;
os << space( indent ) << "minimum: " << minimum << std::endl;
os << space( indent ) << "maximum: " << maximum << std::endl;
os << space( indent ) << "scale: " << scale << std::endl;
os << space( indent ) << "offset: " << offset << std::endl;
os << space( indent ) << "precision: " << precision << std::endl;
os << space( indent ) << "floatMinimum: " << floatMinimum << std::endl;
os << space( indent ) << "floatMaximum: " << floatMaximum << std::endl;
os << space( indent ) << "fileOffset: " << fileOffset << std::endl;
os << space( indent ) << "length: " << length << std::endl;
os << space( indent ) << "allowHeterogeneousChildren: " << allowHeterogeneousChildren << std::endl;
os << space( indent ) << "recordCount: " << recordCount << std::endl;
if ( container_ni )
{
os << space( indent ) << "container_ni: <defined>" << std::endl;
}
else
{
os << space( indent ) << "container_ni: <null>" << std::endl;
}
os << space( indent ) << "childText: \"" << childText << "\"" << std::endl;
}
//=============================================================================
// E57XmlParser
E57XmlParser::E57XmlParser( ImageFileImplSharedPtr imf ) : imf_( imf ), xmlReader( nullptr )
{
}
E57XmlParser::~E57XmlParser()
{
delete xmlReader;
xmlReader = nullptr;
XMLPlatformUtils::Terminate();
}
void E57XmlParser::init()
{
// Initialize the XML4C2 system
try
{
XMLPlatformUtils::Initialize();
}
catch ( const XMLException &ex )
{
/// Turn parser exception into E57Exception
throw E57_EXCEPTION2( E57_ERROR_XML_PARSER_INIT,
"parserMessage=" + ustring( XMLString::transcode( ex.getMessage() ) ) );
}
xmlReader = XMLReaderFactory::createXMLReader(); //??? auto_ptr?
if ( !xmlReader )
{
throw E57_EXCEPTION2( E57_ERROR_XML_PARSER_INIT, "could not create the xml reader" );
}
//??? check these are right
xmlReader->setFeature( XMLUni::fgSAX2CoreValidation, true );
xmlReader->setFeature( XMLUni::fgXercesDynamic, true );
xmlReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
xmlReader->setFeature( XMLUni::fgXercesSchema, true );
xmlReader->setFeature( XMLUni::fgXercesSchemaFullChecking, true );
xmlReader->setFeature( XMLUni::fgSAX2CoreNameSpacePrefixes, true );
xmlReader->setContentHandler( this );
xmlReader->setErrorHandler( this );
}
void E57XmlParser::parse( InputSource &inputSource )
{
xmlReader->parse( inputSource );
}
void E57XmlParser::startElement( const XMLCh *const uri, const XMLCh *const localName, const XMLCh *const qName,
const Attributes &attributes )
{
#ifdef E57_MAX_VERBOSE
std::cout << "startElement" << std::endl;
std::cout << space( 2 ) << "URI: " << toUString( uri ) << std::endl;
std::cout << space( 2 ) << "localName: " << toUString( localName ) << std::endl;
std::cout << space( 2 ) << "qName: " << toUString( qName ) << std::endl;
for ( size_t i = 0; i < attributes.getLength(); i++ )
{
std::cout << space( 2 ) << "Attribute[" << i << "]" << std::endl;
std::cout << space( 4 ) << "URI: " << toUString( attributes.getURI( i ) ) << std::endl;
std::cout << space( 4 ) << "localName: " << toUString( attributes.getLocalName( i ) ) << std::endl;
std::cout << space( 4 ) << "qName: " << toUString( attributes.getQName( i ) ) << std::endl;
std::cout << space( 4 ) << "value: " << toUString( attributes.getValue( i ) ) << std::endl;
}
#endif
/// Get Type attribute
ustring node_type = lookupAttribute( attributes, att_type );
//??? check to make sure not in primitive type (can only nest inside compound
// types).
ParseInfo pi;
if ( node_type == "Integer" )
{
#ifdef E57_MAX_VERBOSE
std::cout << "got a Integer" << std::endl;
#endif
//??? check validity of numeric strings
pi.nodeType = E57_INTEGER;
if ( isAttributeDefined( attributes, att_minimum ) )
{
ustring minimum_str = lookupAttribute( attributes, att_minimum );
pi.minimum = convertStrToLL( minimum_str );
}
else
{
/// Not defined defined in XML, so defaults to E57_INT64_MIN
pi.minimum = E57_INT64_MIN;
}
if ( isAttributeDefined( attributes, att_maximum ) )
{
ustring maximum_str = lookupAttribute( attributes, att_maximum );
pi.maximum = convertStrToLL( maximum_str );
}
else
{
/// Not defined defined in XML, so defaults to E57_INT64_MAX
pi.maximum = E57_INT64_MAX;
}
/// Push info so far onto stack
stack_.push( pi );
}
else if ( node_type == "ScaledInteger" )
{
#ifdef E57_MAX_VERBOSE
std::cout << "got a ScaledInteger" << std::endl;
#endif
pi.nodeType = E57_SCALED_INTEGER;
//??? check validity of numeric strings
if ( isAttributeDefined( attributes, att_minimum ) )
{
ustring minimum_str = lookupAttribute( attributes, att_minimum );
pi.minimum = convertStrToLL( minimum_str );
}
else
{
/// Not defined defined in XML, so defaults to E57_INT64_MIN
pi.minimum = E57_INT64_MIN;
}
if ( isAttributeDefined( attributes, att_maximum ) )
{
ustring maximum_str = lookupAttribute( attributes, att_maximum );
pi.maximum = convertStrToLL( maximum_str );
}
else
{
/// Not defined defined in XML, so defaults to E57_INT64_MAX
pi.maximum = E57_INT64_MAX;
}
if ( isAttributeDefined( attributes, att_scale ) )
{
ustring scale_str = lookupAttribute( attributes, att_scale );
pi.scale = atof( scale_str.c_str() ); //??? use exact rounding library
}
else
{
/// Not defined defined in XML, so defaults to 1.0
pi.scale = 1.0;
}
if ( isAttributeDefined( attributes, att_offset ) )
{
ustring offset_str = lookupAttribute( attributes, att_offset );
pi.offset = atof( offset_str.c_str() ); //??? use exact rounding library
}
else
{
/// Not defined defined in XML, so defaults to 0.0
pi.offset = 0.0;
}
/// Push info so far onto stack
stack_.push( pi );
}
else if ( node_type == "Float" )
{
#ifdef E57_MAX_VERBOSE
std::cout << "got a Float" << std::endl;
#endif
pi.nodeType = E57_FLOAT;
if ( isAttributeDefined( attributes, att_precision ) )
{
ustring precision_str = lookupAttribute( attributes, att_precision );
if ( precision_str == "single" )
{
pi.precision = E57_SINGLE;
}
else if ( precision_str == "double" )
{
pi.precision = E57_DOUBLE;
}
else
{
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT,
"precisionString=" + precision_str + " fileName=" + imf_->fileName() +
" uri=" + toUString( uri ) + " localName=" + toUString( localName ) +
" qName=" + toUString( qName ) );
}
}
else
{
/// Not defined defined in XML, so defaults to double
pi.precision = E57_DOUBLE;
}
if ( isAttributeDefined( attributes, att_minimum ) )
{
ustring minimum_str = lookupAttribute( attributes, att_minimum );
pi.floatMinimum = atof( minimum_str.c_str() ); //??? use exact rounding library
}
else
{
/// Not defined defined in XML, so defaults to E57_FLOAT_MIN or
/// E57_DOUBLE_MIN
if ( pi.precision == E57_SINGLE )
{
pi.floatMinimum = E57_FLOAT_MIN;
}
else
{
pi.floatMinimum = E57_DOUBLE_MIN;
}
}
if ( isAttributeDefined( attributes, att_maximum ) )
{
ustring maximum_str = lookupAttribute( attributes, att_maximum );
pi.floatMaximum = atof( maximum_str.c_str() ); //??? use exact rounding library
}
else
{
/// Not defined defined in XML, so defaults to FLOAT_MAX or DOUBLE_MAX
if ( pi.precision == E57_SINGLE )
{
pi.floatMaximum = E57_FLOAT_MAX;
}
else
{
pi.floatMaximum = E57_DOUBLE_MAX;
}
}
/// Push info so far onto stack
stack_.push( pi );
}
else if ( node_type == "String" )
{
#ifdef E57_MAX_VERBOSE
std::cout << "got a String" << std::endl;
#endif
pi.nodeType = E57_STRING;
/// Push info so far onto stack
stack_.push( pi );
}
else if ( node_type == "Blob" )
{
#ifdef E57_MAX_VERBOSE
std::cout << "got a Blob" << std::endl;
#endif
pi.nodeType = E57_BLOB;
//??? check validity of numeric strings
/// fileOffset is required to be defined
ustring fileOffset_str = lookupAttribute( attributes, att_fileOffset );
pi.fileOffset = convertStrToLL( fileOffset_str );
/// length is required to be defined
ustring length_str = lookupAttribute( attributes, att_length );
pi.length = convertStrToLL( length_str );
/// Push info so far onto stack
stack_.push( pi );
}
else if ( node_type == "Structure" )
{
#ifdef E57_MAX_VERBOSE
std::cout << "got a Structure" << std::endl;
#endif
pi.nodeType = E57_STRUCTURE;
/// Read name space decls, if e57Root element
if ( toUString( localName ) == "e57Root" )
{
/// Search attributes for namespace declarations (only allowed in
/// E57Root structure)
bool gotDefault = false;
for ( size_t i = 0; i < attributes.getLength(); i++ )
{
/// Check if declaring the default namespace
if ( toUString( attributes.getQName( i ) ) == "xmlns" )
{
#ifdef E57_VERBOSE
std::cout << "declared default namespace, URI=" << toUString( attributes.getValue( i ) ) << std::endl;
#endif
imf_->extensionsAdd( "", toUString( attributes.getValue( i ) ) );
gotDefault = true;
}
/// Check if declaring a namespace
if ( toUString( attributes.getURI( i ) ) == "http://www.w3.org/2000/xmlns/" )
{
#ifdef E57_VERBOSE
std::cout << "declared extension, prefix=" << toUString( attributes.getLocalName( i ) )
<< " URI=" << toUString( attributes.getValue( i ) ) << std::endl;
#endif
imf_->extensionsAdd( toUString( attributes.getLocalName( i ) ), toUString( attributes.getValue( i ) ) );
}
}
/// If didn't declare a default namespace, have error
if ( !gotDefault )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT,
"fileName=" + imf_->fileName() + " uri=" + toUString( uri ) +
" localName=" + toUString( localName ) + " qName=" + toUString( qName ) );
}
}
/// Create container now, so can hold children
std::shared_ptr<StructureNodeImpl> s_ni( new StructureNodeImpl( imf_ ) );
pi.container_ni = s_ni;
/// After have Structure, check again if E57Root, if so mark attached so
/// all children will be attached when added
if ( toUString( localName ) == "e57Root" )
{
s_ni->setAttachedRecursive();
}
/// Push info so far onto stack
stack_.push( pi );
}
else if ( node_type == "Vector" )
{
#ifdef E57_MAX_VERBOSE
std::cout << "got a Vector" << std::endl;
#endif
pi.nodeType = E57_VECTOR;
if ( isAttributeDefined( attributes, att_allowHeterogeneousChildren ) )
{
ustring allowHetero_str = lookupAttribute( attributes, att_allowHeterogeneousChildren );
int64_t i64 = convertStrToLL( allowHetero_str );
if ( i64 == 0 )
{
pi.allowHeterogeneousChildren = false;
}
else if ( i64 == 1 )
{
pi.allowHeterogeneousChildren = true;
}
else
{
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT,
"allowHeterogeneousChildren=" + toString( i64 ) + "fileName=" + imf_->fileName() +
" uri=" + toUString( uri ) + " localName=" + toUString( localName ) +
" qName=" + toUString( qName ) );
}
}
else
{
/// Not defined defined in XML, so defaults to false
pi.allowHeterogeneousChildren = false;
}
/// Create container now, so can hold children
std::shared_ptr<VectorNodeImpl> v_ni( new VectorNodeImpl( imf_, pi.allowHeterogeneousChildren ) );
pi.container_ni = v_ni;
/// Push info so far onto stack
stack_.push( pi );
}
else if ( node_type == "CompressedVector" )
{
#ifdef E57_MAX_VERBOSE
std::cout << "got a CompressedVector" << std::endl;
#endif
pi.nodeType = E57_COMPRESSED_VECTOR;
/// fileOffset is required to be defined
ustring fileOffset_str = lookupAttribute( attributes, att_fileOffset );
pi.fileOffset = convertStrToLL( fileOffset_str );
/// recordCount is required to be defined
ustring recordCount_str = lookupAttribute( attributes, att_recordCount );
pi.recordCount = convertStrToLL( recordCount_str );
/// Create container now, so can hold children
std::shared_ptr<CompressedVectorNodeImpl> cv_ni( new CompressedVectorNodeImpl( imf_ ) );
cv_ni->setRecordCount( pi.recordCount );
cv_ni->setBinarySectionLogicalStart(
imf_->file_->physicalToLogical( pi.fileOffset ) ); //??? what if file_ is NULL?
pi.container_ni = cv_ni;
/// Push info so far onto stack
stack_.push( pi );
}
else
{
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT,
"nodeType=" + node_type + " fileName=" + imf_->fileName() + " uri=" + toUString( uri ) +
" localName=" + toUString( localName ) + " qName=" + toUString( qName ) );
}
#ifdef E57_MAX_VERBOSE
pi.dump( 4 );
#endif
}
void E57XmlParser::endElement( const XMLCh *const uri, const XMLCh *const localName, const XMLCh *const qName )
{
#ifdef E57_MAX_VERBOSE
std::cout << "endElement" << std::endl;
#endif
/// Pop the node that just ended
ParseInfo pi = stack_.top(); //??? really want to make a copy here?
stack_.pop();
#ifdef E57_MAX_VERBOSE
pi.dump( 4 );
#endif
/// We should now have all the info we need to create the node
NodeImplSharedPtr current_ni;
switch ( pi.nodeType )
{
case E57_STRUCTURE:
case E57_VECTOR:
current_ni = pi.container_ni;
break;
case E57_COMPRESSED_VECTOR:
{
/// Verify that both prototype and codecs child elements were defined
/// ???
current_ni = pi.container_ni;
}
break;
case E57_INTEGER:
{
/// Convert child text (if any) to value, else default to 0.0
int64_t intValue;
if ( pi.childText.length() > 0 )
{
intValue = convertStrToLL( pi.childText );
}
else
{
intValue = 0;
}
std::shared_ptr<IntegerNodeImpl> i_ni( new IntegerNodeImpl( imf_, intValue, pi.minimum, pi.maximum ) );
current_ni = i_ni;
}
break;
case E57_SCALED_INTEGER:
{
/// Convert child text (if any) to value, else default to 0.0
int64_t intValue;
if ( pi.childText.length() > 0 )
{
intValue = convertStrToLL( pi.childText );
}
else
{
intValue = 0;
}
std::shared_ptr<ScaledIntegerNodeImpl> si_ni(
new ScaledIntegerNodeImpl( imf_, intValue, pi.minimum, pi.maximum, pi.scale, pi.offset ) );
current_ni = si_ni;
}
break;
case E57_FLOAT:
{
/// Convert child text (if any) to value, else default to 0.0
double floatValue;
if ( pi.childText.length() > 0 )
{
floatValue = atof( pi.childText.c_str() );
}
else
{
floatValue = 0.0;
}
std::shared_ptr<FloatNodeImpl> f_ni(
new FloatNodeImpl( imf_, floatValue, pi.precision, pi.floatMinimum, pi.floatMaximum ) );
current_ni = f_ni;
}
break;
case E57_STRING:
{
std::shared_ptr<StringNodeImpl> s_ni( new StringNodeImpl( imf_, pi.childText ) );
current_ni = s_ni;
}
break;
case E57_BLOB:
{
std::shared_ptr<BlobNodeImpl> b_ni( new BlobNodeImpl( imf_, pi.fileOffset, pi.length ) );
current_ni = b_ni;
}
break;
default:
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "nodeType=" + toString( pi.nodeType ) +
" fileName=" + imf_->fileName() + " uri=" + toUString( uri ) +
" localName=" + toUString( localName ) +
" qName=" + toUString( qName ) );
}
#ifdef E57_MAX_VERBOSE
current_ni->dump( 4 );
#endif
/// If first node in file ended, we are all done
if ( stack_.empty() )
{
/// Top level should be Structure
if ( current_ni->type() != E57_STRUCTURE )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT,
"currentType=" + toString( current_ni->type() ) + " fileName=" + imf_->fileName() +
" uri=" + toUString( uri ) + " localName=" + toUString( localName ) +
" qName=" + toUString( qName ) );
}
imf_->root_ = std::static_pointer_cast<StructureNodeImpl>( current_ni );
return;
}
/// Get next level up node (when entered function), which should be a
/// container.
NodeImplSharedPtr parent_ni = stack_.top().container_ni;
if ( !parent_ni )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT, "fileName=" + imf_->fileName() + " uri=" + toUString( uri ) +
" localName=" + toUString( localName ) +
" qName=" + toUString( qName ) );
}
/// Add current node into parent at top of stack
switch ( parent_ni->type() )
{
case E57_STRUCTURE:
{
std::shared_ptr<StructureNodeImpl> struct_ni = std::static_pointer_cast<StructureNodeImpl>( parent_ni );
/// Add named child to structure
struct_ni->set( toUString( qName ), current_ni );
}
break;
case E57_VECTOR:
{
std::shared_ptr<VectorNodeImpl> vector_ni = std::static_pointer_cast<VectorNodeImpl>( parent_ni );
/// Add unnamed child to vector
vector_ni->append( current_ni );
}
break;
case E57_COMPRESSED_VECTOR:
{
std::shared_ptr<CompressedVectorNodeImpl> cv_ni =
std::static_pointer_cast<CompressedVectorNodeImpl>( parent_ni );
ustring uQName = toUString( qName );
/// n can be either prototype or codecs
if ( uQName == "prototype" )
{
cv_ni->setPrototype( current_ni );
}
else if ( uQName == "codecs" )
{
if ( current_ni->type() != E57_VECTOR )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT,
"currentType=" + toString( current_ni->type() ) + " fileName=" + imf_->fileName() +
" uri=" + toUString( uri ) + " localName=" + toUString( localName ) +
" qName=" + toUString( qName ) );
}
std::shared_ptr<VectorNodeImpl> vi = std::static_pointer_cast<VectorNodeImpl>( current_ni );
/// Check VectorNode is hetero
if ( !vi->allowHeteroChildren() )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT,
"currentType=" + toString( current_ni->type() ) + " fileName=" + imf_->fileName() +
" uri=" + toUString( uri ) + " localName=" + toUString( localName ) +
" qName=" + toUString( qName ) );
}
cv_ni->setCodecs( vi );
}
else
{
/// Found unknown XML child element of CompressedVector, not
/// prototype or codecs
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT,
+"fileName=" + imf_->fileName() + " uri=" + toUString( uri ) +
" localName=" + toUString( localName ) + " qName=" + toUString( qName ) );
}
}
break;
default:
/// Have bad XML nesting, parent should have been a container.
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT,
"parentType=" + toString( parent_ni->type() ) + " fileName=" + imf_->fileName() +
" uri=" + toUString( uri ) + " localName=" + toUString( localName ) +
" qName=" + toUString( qName ) );
}
}
void E57XmlParser::characters( const XMLCh *const chars, const XMLSize_t length )
{
(void)length;
//??? use length to make ustring
#ifdef E57_MAX_VERBOSE
std::cout << "characters, chars=\"" << toUString( chars ) << "\" length=" << length << std::endl;
#endif
/// Get active element
ParseInfo &pi = stack_.top();
/// Check if child text is allowed for current E57 element type
switch ( pi.nodeType )
{
case E57_STRUCTURE:
case E57_VECTOR:
case E57_COMPRESSED_VECTOR:
case E57_BLOB:
{
/// If characters aren't whitespace, have an error, else ignore
ustring s = toUString( chars );
if ( s.find_first_not_of( " \t\n\r" ) != std::string::npos )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT, "chars=" + toUString( chars ) );
}
}
break;
default:
/// Append to any previous characters
pi.childText += toUString( chars );
}
}
void E57XmlParser::error( const SAXParseException &ex )
{
throw E57_EXCEPTION2( E57_ERROR_XML_PARSER, "systemId=" + ustring( XMLString::transcode( ex.getSystemId() ) ) +
" xmlLine=" + toString( ex.getLineNumber() ) +
" xmlColumn=" + toString( ex.getColumnNumber() ) + " parserMessage=" +
ustring( XMLString::transcode( ex.getMessage() ) ) );
}
void E57XmlParser::fatalError( const SAXParseException &ex )
{
throw E57_EXCEPTION2( E57_ERROR_XML_PARSER, "systemId=" + ustring( XMLString::transcode( ex.getSystemId() ) ) +
" xmlLine=" + toString( ex.getLineNumber() ) +
" xmlColumn=" + toString( ex.getColumnNumber() ) + " parserMessage=" +
ustring( XMLString::transcode( ex.getMessage() ) ) );
}
void E57XmlParser::warning( const SAXParseException &ex )
{
/// Don't take any action on warning from parser, just report
std::cerr << "**** XML parser warning: " << ustring( XMLString::transcode( ex.getMessage() ) ) << std::endl;
std::cerr << " Debug info:" << std::endl;
std::cerr << " systemId=" << XMLString::transcode( ex.getSystemId() ) << std::endl;
std::cerr << ", xmlLine=" << ex.getLineNumber() << std::endl;
std::cerr << ", xmlColumn=" << ex.getColumnNumber() << std::endl;
}
ustring E57XmlParser::toUString( const XMLCh *const xml_str )
{
ustring u_str;
if ( xml_str && *xml_str )
{
TranscodeToStr UTF8Transcoder( xml_str, "UTF-8" );
u_str = ustring( reinterpret_cast<const char *>( UTF8Transcoder.str() ) );
}
return ( u_str );
}
ustring E57XmlParser::lookupAttribute( const Attributes &attributes, const XMLCh *attribute_name )
{
XMLSize_t attr_index;
if ( !attributes.getIndex( attribute_name, attr_index ) )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_XML_FORMAT, "attributeName=" + toUString( attribute_name ) );
}
return ( toUString( attributes.getValue( attr_index ) ) );
}
bool E57XmlParser::isAttributeDefined( const Attributes &attributes, const XMLCh *attribute_name )
{
XMLSize_t attr_index;
return ( attributes.getIndex( attribute_name, attr_index ) );
}

View File

@@ -1,126 +0,0 @@
/*
* 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_;
};
}

View File

@@ -1,977 +0,0 @@
/*
* 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.
*/
#include <algorithm>
#include <cstring>
#include "CompressedVectorNodeImpl.h"
#include "Encoder.h"
#include "FloatNodeImpl.h"
#include "ImageFileImpl.h"
#include "IntegerNodeImpl.h"
#include "Packet.h"
#include "ScaledIntegerNodeImpl.h"
#include "SourceDestBufferImpl.h"
using namespace e57;
std::shared_ptr<Encoder> Encoder::EncoderFactory( unsigned bytestreamNumber,
std::shared_ptr<CompressedVectorNodeImpl> cVector,
std::vector<SourceDestBuffer> &sbufs, ustring & /*codecPath*/ )
{
//??? For now, only handle one input
if ( sbufs.size() != 1 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "sbufsSize=" + toString( sbufs.size() ) );
}
SourceDestBuffer sbuf = sbufs.at( 0 );
/// Get node we are going to encode from the CompressedVector's prototype
NodeImplSharedPtr prototype = cVector->getPrototype();
ustring path = sbuf.pathName();
NodeImplSharedPtr encodeNode = prototype->get( path );
#ifdef E57_MAX_VERBOSE
std::cout << "Node to encode:" << std::endl; //???
encodeNode->dump( 2 );
#endif
switch ( encodeNode->type() )
{
case E57_INTEGER:
{
std::shared_ptr<IntegerNodeImpl> ini =
std::static_pointer_cast<IntegerNodeImpl>( encodeNode ); // downcast to correct type
/// Get pointer to parent ImageFileImpl, to call bitsNeeded()
ImageFileImplSharedPtr imf( encodeNode->destImageFile_ ); //??? should be function for this,
// imf->parentFile()
//--> ImageFile?
unsigned bitsPerRecord = imf->bitsNeeded( ini->minimum(), ini->maximum() );
//!!! need to pick smarter channel buffer sizes, here and elsewhere
/// Construct Integer encoder with appropriate register size, based on
/// number of bits stored.
if ( bitsPerRecord == 0 )
{
std::shared_ptr<Encoder> encoder( new ConstantIntegerEncoder( bytestreamNumber, sbuf, ini->minimum() ) );
return encoder;
}
if ( bitsPerRecord <= 8 )
{
std::shared_ptr<Encoder> encoder( new BitpackIntegerEncoder<uint8_t>(
false, bytestreamNumber, sbuf, DATA_PACKET_MAX /*!!!*/, ini->minimum(), ini->maximum(), 1.0, 0.0 ) );
return encoder;
}
if ( bitsPerRecord <= 16 )
{
std::shared_ptr<Encoder> encoder( new BitpackIntegerEncoder<uint16_t>(
false, bytestreamNumber, sbuf, DATA_PACKET_MAX /*!!!*/, ini->minimum(), ini->maximum(), 1.0, 0.0 ) );
return encoder;
}
if ( bitsPerRecord <= 32 )
{
std::shared_ptr<Encoder> encoder( new BitpackIntegerEncoder<uint32_t>(
false, bytestreamNumber, sbuf, DATA_PACKET_MAX /*!!!*/, ini->minimum(), ini->maximum(), 1.0, 0.0 ) );
return encoder;
}
std::shared_ptr<Encoder> encoder( new BitpackIntegerEncoder<uint64_t>(
false, bytestreamNumber, sbuf, DATA_PACKET_MAX /*!!!*/, ini->minimum(), ini->maximum(), 1.0, 0.0 ) );
return encoder;
}
case E57_SCALED_INTEGER:
{
std::shared_ptr<ScaledIntegerNodeImpl> sini =
std::static_pointer_cast<ScaledIntegerNodeImpl>( encodeNode ); // downcast to correct type
/// Get pointer to parent ImageFileImpl, to call bitsNeeded()
ImageFileImplSharedPtr imf( encodeNode->destImageFile_ ); //??? should be function for this,
// imf->parentFile()
//--> ImageFile?
unsigned bitsPerRecord = imf->bitsNeeded( sini->minimum(), sini->maximum() );
//!!! need to pick smarter channel buffer sizes, here and elsewhere
/// Construct ScaledInteger encoder with appropriate register size,
/// based on number of bits stored.
if ( bitsPerRecord == 0 )
{
std::shared_ptr<Encoder> encoder( new ConstantIntegerEncoder( bytestreamNumber, sbuf, sini->minimum() ) );
return encoder;
}
if ( bitsPerRecord <= 8 )
{
std::shared_ptr<Encoder> encoder(
new BitpackIntegerEncoder<uint8_t>( true, bytestreamNumber, sbuf, DATA_PACKET_MAX /*!!!*/,
sini->minimum(), sini->maximum(), sini->scale(), sini->offset() ) );
return encoder;
}
if ( bitsPerRecord <= 16 )
{
std::shared_ptr<Encoder> encoder(
new BitpackIntegerEncoder<uint16_t>( true, bytestreamNumber, sbuf, DATA_PACKET_MAX /*!!!*/,
sini->minimum(), sini->maximum(), sini->scale(), sini->offset() ) );
return encoder;
}
if ( bitsPerRecord <= 32 )
{
std::shared_ptr<Encoder> encoder(
new BitpackIntegerEncoder<uint32_t>( true, bytestreamNumber, sbuf, DATA_PACKET_MAX /*!!!*/,
sini->minimum(), sini->maximum(), sini->scale(), sini->offset() ) );
return encoder;
}
std::shared_ptr<Encoder> encoder(
new BitpackIntegerEncoder<uint64_t>( true, bytestreamNumber, sbuf, DATA_PACKET_MAX /*!!!*/, sini->minimum(),
sini->maximum(), sini->scale(), sini->offset() ) );
return encoder;
}
case E57_FLOAT:
{
std::shared_ptr<FloatNodeImpl> fni =
std::static_pointer_cast<FloatNodeImpl>( encodeNode ); // downcast to correct type
//!!! need to pick smarter channel buffer sizes, here and elsewhere
std::shared_ptr<Encoder> encoder(
new BitpackFloatEncoder( bytestreamNumber, sbuf, DATA_PACKET_MAX /*!!!*/, fni->precision() ) );
return encoder;
}
case E57_STRING:
{
std::shared_ptr<Encoder> encoder(
new BitpackStringEncoder( bytestreamNumber, sbuf, DATA_PACKET_MAX /*!!!*/ ) );
return encoder;
}
default:
{
throw E57_EXCEPTION2( E57_ERROR_BAD_PROTOTYPE, "nodeType=" + toString( encodeNode->type() ) );
}
}
}
Encoder::Encoder( unsigned bytestreamNumber ) : bytestreamNumber_( bytestreamNumber )
{
}
#ifdef E57_DEBUG
void Encoder::dump( int indent, std::ostream &os ) const
{
os << space( indent ) << "bytestreamNumber: " << bytestreamNumber_ << std::endl;
}
#endif
///================
BitpackEncoder::BitpackEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf, unsigned outputMaxSize,
unsigned alignmentSize ) :
Encoder( bytestreamNumber ),
sourceBuffer_( sbuf.impl() ), outBuffer_( outputMaxSize ), outBufferFirst_( 0 ), outBufferEnd_( 0 ),
outBufferAlignmentSize_( alignmentSize ), currentRecordIndex_( 0 )
{
}
unsigned BitpackEncoder::sourceBufferNextIndex()
{
return ( sourceBuffer_->nextIndex() );
}
uint64_t BitpackEncoder::currentRecordIndex()
{
return ( currentRecordIndex_ );
}
size_t BitpackEncoder::outputAvailable() const
{
return outBufferEnd_ - outBufferFirst_;
}
void BitpackEncoder::outputRead( char *dest, const size_t byteCount )
{
#ifdef E57_MAX_VERBOSE
std::cout << "BitpackEncoder::outputRead() called, dest=" << dest << " byteCount=" << byteCount << std::endl; //???
#endif
/// Check we have enough bytes in queue
if ( byteCount > outputAvailable() )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "byteCount=" + toString( byteCount ) +
" outputAvailable=" + toString( outputAvailable() ) );
}
/// Copy output bytes to caller
memcpy( dest, &outBuffer_[outBufferFirst_], byteCount );
#ifdef E57_MAX_VERBOSE
{
unsigned i;
for ( i = 0; i < byteCount && i < 20; i++ )
{
std::cout << " outBuffer[" << outBufferFirst_ + i
<< "]=" << static_cast<unsigned>( static_cast<unsigned char>( outBuffer_[outBufferFirst_ + i] ) )
<< std::endl; //???
}
if ( i < byteCount )
{
std::cout << " " << byteCount - 1 << " bytes unprinted..." << std::endl;
}
}
#endif
/// Advance head pointer.
outBufferFirst_ += byteCount;
/// Don't slide remaining data down now, wait until do some more processing
/// (that's when data needs to be aligned).
}
void BitpackEncoder::outputClear()
{
outBufferFirst_ = 0;
outBufferEnd_ = 0;
}
void BitpackEncoder::sourceBufferSetNew( std::vector<SourceDestBuffer> &sbufs )
{
/// Verify that this encoder only has single input buffer
if ( sbufs.size() != 1 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "sbufsSize=" + toString( sbufs.size() ) );
}
sourceBuffer_ = sbufs.at( 0 ).impl();
}
size_t BitpackEncoder::outputGetMaxSize()
{
/// Its size that matters here, not capacity
return ( outBuffer_.size() );
}
void BitpackEncoder::outputSetMaxSize( unsigned byteCount )
{
/// Ignore if trying to shrink buffer (queue might get messed up).
if ( byteCount > outBuffer_.size() )
{
outBuffer_.resize( byteCount );
}
}
void BitpackEncoder::outBufferShiftDown()
{
/// Move data down closer to beginning of outBuffer_.
/// But keep outBufferEnd_ as a multiple of outBufferAlignmentSize_.
/// This ensures that writes into buffer can occur on natural boundaries.
/// Otherwise some CPUs will fault.
if ( outBufferFirst_ == outBufferEnd_ )
{
/// Buffer is empty, reset indices to 0
outBufferFirst_ = 0;
outBufferEnd_ = 0;
return;
}
/// Round newEnd up to nearest multiple of outBufferAlignmentSize_.
size_t newEnd = outputAvailable();
size_t remainder = newEnd % outBufferAlignmentSize_;
if ( remainder > 0 )
{
newEnd += outBufferAlignmentSize_ - remainder;
}
size_t newFirst = outBufferFirst_ - ( outBufferEnd_ - newEnd );
size_t byteCount = outBufferEnd_ - outBufferFirst_;
/// Double check round up worked
if ( newEnd % outBufferAlignmentSize_ )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "newEnd=" + toString( newEnd ) +
" outBufferAlignmentSize=" + toString( outBufferAlignmentSize_ ) );
}
/// Be paranoid before memory copy
if ( newFirst + byteCount > outBuffer_.size() )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "newFirst=" + toString( newFirst ) +
" byteCount=" + toString( byteCount ) +
" outBufferSize=" + toString( outBuffer_.size() ) );
}
/// Move available data down closer to beginning of outBuffer_. Overlapping
/// regions ok with memmove().
memmove( &outBuffer_[newFirst], &outBuffer_[outBufferFirst_], byteCount );
/// Update indexes
outBufferFirst_ = newFirst;
outBufferEnd_ = newEnd;
}
#ifdef E57_DEBUG
void BitpackEncoder::dump( int indent, std::ostream &os ) const
{
Encoder::dump( indent, os );
os << space( indent ) << "sourceBuffer:" << std::endl;
sourceBuffer_->dump( indent + 4, os );
os << space( indent ) << "outBuffer.size: " << outBuffer_.size() << std::endl;
os << space( indent ) << "outBufferFirst: " << outBufferFirst_ << std::endl;
os << space( indent ) << "outBufferEnd: " << outBufferEnd_ << std::endl;
os << space( indent ) << "outBufferAlignmentSize: " << outBufferAlignmentSize_ << std::endl;
os << space( indent ) << "currentRecordIndex: " << currentRecordIndex_ << std::endl;
os << space( indent ) << "outBuffer:" << std::endl;
unsigned i;
for ( i = 0; i < outBuffer_.size() && i < 20; i++ )
{
os << space( indent + 4 ) << "outBuffer[" << i
<< "]: " << static_cast<unsigned>( static_cast<unsigned char>( outBuffer_.at( i ) ) ) << std::endl;
}
if ( i < outBuffer_.size() )
{
os << space( indent + 4 ) << outBuffer_.size() - i << " more unprinted..." << std::endl;
}
}
#endif
//================
BitpackFloatEncoder::BitpackFloatEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf, unsigned outputMaxSize,
FloatPrecision precision ) :
BitpackEncoder( bytestreamNumber, sbuf, outputMaxSize,
( precision == E57_SINGLE ) ? sizeof( float ) : sizeof( double ) ),
precision_( precision )
{
}
uint64_t BitpackFloatEncoder::processRecords( size_t recordCount )
{
#ifdef E57_MAX_VERBOSE
std::cout << " BitpackFloatEncoder::processRecords() called, recordCount=" << recordCount << std::endl; //???
#endif
/// Before we add any more, try to shift current contents of outBuffer_ down
/// to beginning of buffer. This leaves outBufferEnd_ at a natural boundary.
outBufferShiftDown();
size_t typeSize = ( precision_ == E57_SINGLE ) ? sizeof( float ) : sizeof( double );
#ifdef E57_DEBUG
/// Verify that outBufferEnd_ is multiple of typeSize (so transfers of floats
/// are aligned naturally in memory).
if ( outBufferEnd_ % typeSize )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL,
"outBufferEnd=" + toString( outBufferEnd_ ) + " typeSize=" + toString( typeSize ) );
}
#endif
/// Figure out how many records will fit in output.
size_t maxOutputRecords = ( outBuffer_.size() - outBufferEnd_ ) / typeSize;
/// Can't process more records than will safely fit in output stream
if ( recordCount > maxOutputRecords )
{
recordCount = maxOutputRecords;
}
if ( precision_ == E57_SINGLE )
{
/// Form the starting address for next available location in outBuffer
auto outp = reinterpret_cast<float *>( &outBuffer_[outBufferEnd_] );
/// Copy floats from sourceBuffer_ to outBuffer_
for ( unsigned i = 0; i < recordCount; i++ )
{
outp[i] = sourceBuffer_->getNextFloat();
#ifdef E57_MAX_VERBOSE
std::cout << "encoding float: " << outp[i] << std::endl;
#endif
}
}
else
{ /// E57_DOUBLE precision
/// Form the starting address for next available location in outBuffer
auto outp = reinterpret_cast<double *>( &outBuffer_[outBufferEnd_] );
/// Copy doubles from sourceBuffer_ to outBuffer_
for ( unsigned i = 0; i < recordCount; i++ )
{
outp[i] = sourceBuffer_->getNextDouble();
#ifdef E57_MAX_VERBOSE
std::cout << "encoding double: " << outp[i] << std::endl;
#endif
}
}
/// Update end of outBuffer
outBufferEnd_ += recordCount * typeSize;
/// Update counts of records processed
currentRecordIndex_ += recordCount;
return ( currentRecordIndex_ );
}
bool BitpackFloatEncoder::registerFlushToOutput()
{
/// Since have no registers in encoder, return success
return ( true );
}
float BitpackFloatEncoder::bitsPerRecord()
{
return ( ( precision_ == E57_SINGLE ) ? 32.0F : 64.0F );
}
#ifdef E57_DEBUG
void BitpackFloatEncoder::dump( int indent, std::ostream &os ) const
{
BitpackEncoder::dump( indent, os );
if ( precision_ == E57_SINGLE )
{
os << space( indent ) << "precision: E57_SINGLE" << std::endl;
}
else
{
os << space( indent ) << "precision: E57_DOUBLE" << std::endl;
}
}
#endif
//================
BitpackStringEncoder::BitpackStringEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf,
unsigned outputMaxSize ) :
BitpackEncoder( bytestreamNumber, sbuf, outputMaxSize, 1 ),
totalBytesProcessed_( 0 ), isStringActive_( false ), prefixComplete_( false ), currentCharPosition_( 0 )
{
}
uint64_t BitpackStringEncoder::processRecords( size_t recordCount )
{
#ifdef E57_MAX_VERBOSE
std::cout << " BitpackStringEncoder::processRecords() called, recordCount=" << recordCount << std::endl; //???
#endif
/// Before we add any more, try to shift current contents of outBuffer_ down
/// to beginning of buffer.
outBufferShiftDown();
/// Figure out how many bytes outBuffer can accept.
size_t bytesFree = outBuffer_.size() - outBufferEnd_;
/// Form the starting address for next available location in outBuffer
char *outp = &outBuffer_[outBufferEnd_];
unsigned recordsProcessed = 0;
/// Don't start loop unless have at least 8 bytes for worst case string
/// length prefix
while ( recordsProcessed < recordCount && bytesFree >= 8 )
{ //??? should be able to proceed if only 1 byte free
if ( isStringActive_ && !prefixComplete_ )
{
/// Calc the length prefix, either 1 byte or 8 bytes
size_t len = currentString_.length();
if ( len <= 127 )
{
#ifdef E57_MAX_VERBOSE
std::cout << "encoding short string: (len=" << len
<< ") "
""
<< currentString_
<< ""
""
<< std::endl;
#endif
/// We can use the short length prefix: b0=0, b7-b1=len
auto lengthPrefix = static_cast<uint8_t>( len << 1 );
*outp++ = lengthPrefix;
bytesFree--;
}
else
{
#ifdef E57_DEBUG
/// Double check have space
if ( bytesFree < 8 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "bytesFree=" + toString( bytesFree ) );
}
#endif
#ifdef E57_MAX_VERBOSE
std::cout << "encoding long string: (len=" << len
<< ") "
""
<< currentString_
<< ""
""
<< std::endl;
#endif
/// We use the long length prefix: b0=1, b63-b1=len, and store in
/// little endian order Shift the length and set the least
/// significant bit, b0=1.
uint64_t lengthPrefix = ( static_cast<uint64_t>( len ) << 1 ) | 1LL;
*outp++ = static_cast<uint8_t>( lengthPrefix );
*outp++ = static_cast<uint8_t>( lengthPrefix >> ( 1 * 8 ) );
*outp++ = static_cast<uint8_t>( lengthPrefix >> ( 2 * 8 ) );
*outp++ = static_cast<uint8_t>( lengthPrefix >> ( 3 * 8 ) );
*outp++ = static_cast<uint8_t>( lengthPrefix >> ( 4 * 8 ) );
*outp++ = static_cast<uint8_t>( lengthPrefix >> ( 5 * 8 ) );
*outp++ = static_cast<uint8_t>( lengthPrefix >> ( 6 * 8 ) );
*outp++ = static_cast<uint8_t>( lengthPrefix >> ( 7 * 8 ) );
bytesFree -= 8;
}
prefixComplete_ = true;
currentCharPosition_ = 0;
}
if ( isStringActive_ )
{
/// Copy as much string as will fit in outBuffer
size_t bytesToProcess = std::min( currentString_.length() - currentCharPosition_, bytesFree );
for ( size_t i = 0; i < bytesToProcess; i++ )
{
*outp++ = currentString_[currentCharPosition_ + i];
}
currentCharPosition_ += bytesToProcess;
totalBytesProcessed_ += bytesToProcess;
bytesFree -= bytesToProcess;
/// Check if finished string
if ( currentCharPosition_ == currentString_.length() )
{
isStringActive_ = false;
recordsProcessed++;
}
}
if ( !isStringActive_ && recordsProcessed < recordCount )
{
/// Get next string from sourceBuffer
currentString_ = sourceBuffer_->getNextString();
isStringActive_ = true;
prefixComplete_ = false;
currentCharPosition_ = 0;
#ifdef E57_MAX_VERBOSE
std::cout << "getting next string, length=" << currentString_.length() << std::endl;
#endif
}
}
/// Update end of outBuffer
outBufferEnd_ = outBuffer_.size() - bytesFree;
/// Update counts of records processed
currentRecordIndex_ += recordsProcessed;
return ( currentRecordIndex_ );
}
bool BitpackStringEncoder::registerFlushToOutput()
{
/// Since have no registers in encoder, return success
return ( true );
}
float BitpackStringEncoder::bitsPerRecord()
{
/// Return average number of bits in strings + 8 bits for prefix
if ( currentRecordIndex_ > 0 )
{
return ( 8.0f * totalBytesProcessed_ ) / currentRecordIndex_ + 8;
}
/// We haven't completed a record yet, so guess 100 bytes per record
return 100 * 8.0f;
}
#ifdef E57_DEBUG
void BitpackStringEncoder::dump( int indent, std::ostream &os ) const
{
BitpackEncoder::dump( indent, os );
os << space( indent ) << "totalBytesProcessed: " << totalBytesProcessed_ << std::endl;
os << space( indent ) << "isStringActive: " << isStringActive_ << std::endl;
os << space( indent ) << "prefixComplete: " << prefixComplete_ << std::endl;
os << space( indent ) << "currentString: " << currentString_ << std::endl;
os << space( indent ) << "currentCharPosition: " << currentCharPosition_ << std::endl;
}
#endif
//================================================================
template <typename RegisterT>
BitpackIntegerEncoder<RegisterT>::BitpackIntegerEncoder( bool isScaledInteger, unsigned bytestreamNumber,
SourceDestBuffer &sbuf, unsigned outputMaxSize,
int64_t minimum, int64_t maximum, double scale,
double offset ) :
BitpackEncoder( bytestreamNumber, sbuf, outputMaxSize, sizeof( RegisterT ) )
{
/// Get pointer to parent ImageFileImpl
ImageFileImplSharedPtr imf( sbuf.impl()->destImageFile() ); //??? should be function for this,
// imf->parentFile() --> ImageFile?
isScaledInteger_ = isScaledInteger;
minimum_ = minimum;
maximum_ = maximum;
scale_ = scale;
offset_ = offset;
bitsPerRecord_ = imf->bitsNeeded( minimum_, maximum_ );
sourceBitMask_ = ( bitsPerRecord_ == 64 ) ? ~0 : ( 1ULL << bitsPerRecord_ ) - 1;
registerBitsUsed_ = 0;
register_ = 0;
}
template <typename RegisterT> uint64_t BitpackIntegerEncoder<RegisterT>::processRecords( size_t recordCount )
{
//??? what are state guarantees if get an exception during transfer?
#ifdef E57_MAX_VERBOSE
std::cout << "BitpackIntegerEncoder::processRecords() called, sizeof(RegisterT)=" << sizeof( RegisterT )
<< " recordCount=" << recordCount << std::endl;
dump( 4 );
#endif
#ifdef E57_MAX_DEBUG
/// Double check that register will hold at least one input records worth of
/// bits
if ( 8 * sizeof( RegisterT ) < bitsPerRecord_ )
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "bitsPerRecord=" + toString( bitsPerRecord_ ) );
#endif
/// Before we add any more, try to shift current contents of outBuffer_ down
/// to beginning of buffer. This leaves outBufferEnd_ at a natural boundary.
outBufferShiftDown();
#ifdef E57_DEBUG
/// Verify that outBufferEnd_ is multiple of sizeof(RegisterT) (so transfers
/// of RegisterT are aligned naturally in memory).
if ( outBufferEnd_ % sizeof( RegisterT ) )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "outBufferEnd=" + toString( outBufferEnd_ ) );
}
size_t transferMax = ( outBuffer_.size() - outBufferEnd_ ) / sizeof( RegisterT );
#endif
/// Precalculate exact maximum number of records that will fit in output
/// before overflow.
size_t outputWordCapacity = ( outBuffer_.size() - outBufferEnd_ ) / sizeof( RegisterT );
size_t maxOutputRecords =
( outputWordCapacity * 8 * sizeof( RegisterT ) + 8 * sizeof( RegisterT ) - registerBitsUsed_ - 1 ) /
bitsPerRecord_;
/// Number of transfers is the smaller of what was requested and what will
/// fit.
recordCount = std::min( recordCount, maxOutputRecords );
#ifdef E57_MAX_VERBOSE
std::cout << " outputWordCapacity=" << outputWordCapacity << " maxOutputRecords=" << maxOutputRecords
<< " recordCount=" << recordCount << std::endl;
#endif
/// Form the starting address for next available location in outBuffer
auto outp = reinterpret_cast<RegisterT *>( &outBuffer_[outBufferEnd_] );
unsigned outTransferred = 0;
/// Copy bits from sourceBuffer_ to outBuffer_
for ( unsigned i = 0; i < recordCount; i++ )
{
int64_t rawValue;
/// The parameter isScaledInteger_ determines which version of
/// getNextInt64 gets called
if ( isScaledInteger_ )
{
rawValue = sourceBuffer_->getNextInt64( scale_, offset_ );
}
else
{
rawValue = sourceBuffer_->getNextInt64();
}
/// Enforce min/max specification on value
if ( rawValue < minimum_ || maximum_ < rawValue )
{
throw E57_EXCEPTION2( E57_ERROR_VALUE_OUT_OF_BOUNDS, "rawValue=" + toString( rawValue ) +
" minimum=" + toString( minimum_ ) +
" maximum=" + toString( maximum_ ) );
}
auto uValue = static_cast<uint64_t>( rawValue - minimum_ );
#ifdef E57_MAX_VERBOSE
std::cout << "encoding integer rawValue=" << binaryString( rawValue ) << " = " << hexString( rawValue )
<< std::endl;
std::cout << " uValue =" << binaryString( uValue ) << " = " << hexString( uValue ) << std::endl;
#endif
#ifdef E57_DEBUG
/// Double check that no bits outside of the mask are set
if ( uValue & ~static_cast<uint64_t>( sourceBitMask_ ) )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "uValue=" + toString( uValue ) );
}
#endif
/// Mask off upper bits (just in case)
uValue &= static_cast<uint64_t>( sourceBitMask_ );
/// See if uValue bits will fit in register
unsigned newRegisterBitsUsed = registerBitsUsed_ + bitsPerRecord_;
#ifdef E57_MAX_VERBOSE
std::cout << " registerBitsUsed=" << registerBitsUsed_ << " newRegisterBitsUsed=" << newRegisterBitsUsed
<< std::endl;
#endif
if ( newRegisterBitsUsed > 8 * sizeof( RegisterT ) )
{
/// Have more than one registers worth, fill register, transfer, then
/// fill some more
register_ |= static_cast<RegisterT>( uValue ) << registerBitsUsed_;
#ifdef E57_DEBUG
/// Before transfer, double check address within bounds
if ( outTransferred >= transferMax )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "outTransferred=" + toString( outTransferred ) + " transferMax" +
toString( transferMax ) );
}
#endif
outp[outTransferred] = register_;
outTransferred++;
register_ = static_cast<RegisterT>( uValue ) >> ( 8 * sizeof( RegisterT ) - registerBitsUsed_ );
registerBitsUsed_ = newRegisterBitsUsed - 8 * sizeof( RegisterT );
}
else if ( newRegisterBitsUsed == 8 * sizeof( RegisterT ) )
{
/// Input will exactly fill register, insert value, then transfer
register_ |= static_cast<RegisterT>( uValue ) << registerBitsUsed_;
#ifdef E57_DEBUG
/// Before transfer, double check address within bounds
if ( outTransferred >= transferMax )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "outTransferred=" + toString( outTransferred ) + " transferMax" +
toString( transferMax ) );
}
#endif
outp[outTransferred] = register_;
outTransferred++;
register_ = 0;
registerBitsUsed_ = 0;
}
else
{
/// There is extra room in register, insert value, but don't do
/// transfer yet
register_ |= static_cast<RegisterT>( uValue ) << registerBitsUsed_;
registerBitsUsed_ = newRegisterBitsUsed;
}
#ifdef E57_MAX_VERBOSE
std::cout << " After " << outTransferred << " transfers and " << i + 1 << " records, encoder:" << std::endl;
dump( 4 );
#endif
}
/// Update tail of output buffer
outBufferEnd_ += outTransferred * sizeof( RegisterT );
#ifdef E57_DEBUG
/// Double check end is ok
if ( outBufferEnd_ > outBuffer_.size() )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "outBufferEnd=" + toString( outBufferEnd_ ) +
" outBuffersize=" + toString( outBuffer_.size() ) );
}
#endif
/// Update counts of records processed
currentRecordIndex_ += recordCount;
return ( currentRecordIndex_ );
}
template <typename RegisterT> bool BitpackIntegerEncoder<RegisterT>::registerFlushToOutput()
{
#ifdef E57_MAX_VERBOSE
std::cout << "BitpackIntegerEncoder::registerFlushToOutput() called, "
"sizeof(RegisterT)="
<< sizeof( RegisterT ) << std::endl;
dump( 4 );
#endif
/// If have any used bits in register, transfer to output, padded in MSBits
/// with zeros to RegisterT boundary
if ( registerBitsUsed_ > 0 )
{
if ( outBufferEnd_ < outBuffer_.size() - sizeof( RegisterT ) )
{
auto outp = reinterpret_cast<RegisterT *>( &outBuffer_[outBufferEnd_] );
*outp = register_;
register_ = 0;
registerBitsUsed_ = 0;
outBufferEnd_ += sizeof( RegisterT );
return true; // flush succeeded ??? is this used? correctly?
}
return false; // flush didn't complete (not enough room).
}
return true;
}
template <typename RegisterT> float BitpackIntegerEncoder<RegisterT>::bitsPerRecord()
{
return ( static_cast<float>( bitsPerRecord_ ) );
}
#ifdef E57_DEBUG
template <typename RegisterT> void BitpackIntegerEncoder<RegisterT>::dump( int indent, std::ostream &os ) const
{
BitpackEncoder::dump( indent, os );
os << space( indent ) << "isScaledInteger: " << isScaledInteger_ << std::endl;
os << space( indent ) << "minimum: " << minimum_ << std::endl;
os << space( indent ) << "maximum: " << maximum_ << std::endl;
os << space( indent ) << "scale: " << scale_ << std::endl;
os << space( indent ) << "offset: " << offset_ << std::endl;
os << space( indent ) << "bitsPerRecord: " << bitsPerRecord_ << std::endl;
os << space( indent ) << "sourceBitMask: " << binaryString( sourceBitMask_ ) << " " << hexString( sourceBitMask_ )
<< std::endl;
os << space( indent ) << "register: " << binaryString( register_ ) << " " << hexString( register_ )
<< std::endl;
os << space( indent ) << "registerBitsUsed: " << registerBitsUsed_ << std::endl;
}
#endif
//================================================================
ConstantIntegerEncoder::ConstantIntegerEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf, int64_t minimum ) :
Encoder( bytestreamNumber ), sourceBuffer_( sbuf.impl() ), currentRecordIndex_( 0 ), minimum_( minimum )
{
}
uint64_t ConstantIntegerEncoder::processRecords( size_t recordCount )
{
#ifdef E57_MAX_VERBOSE
std::cout << "ConstantIntegerEncoder::processRecords() called, recordCount=" << recordCount << std::endl;
dump( 4 );
#endif
/// Check that all source values are == minimum_
for ( unsigned i = 0; i < recordCount; i++ )
{
int64_t nextInt64 = sourceBuffer_->getNextInt64();
if ( nextInt64 != minimum_ )
{
throw E57_EXCEPTION2( E57_ERROR_VALUE_OUT_OF_BOUNDS,
"nextInt64=" + toString( nextInt64 ) + " minimum=" + toString( minimum_ ) );
}
}
/// Update counts of records processed
currentRecordIndex_ += recordCount;
return ( currentRecordIndex_ );
}
unsigned ConstantIntegerEncoder::sourceBufferNextIndex()
{
return ( sourceBuffer_->nextIndex() );
}
uint64_t ConstantIntegerEncoder::currentRecordIndex()
{
return ( currentRecordIndex_ );
}
float ConstantIntegerEncoder::bitsPerRecord()
{
/// We don't produce any output
return ( 0.0 );
}
bool ConstantIntegerEncoder::registerFlushToOutput()
{
return ( true );
}
size_t ConstantIntegerEncoder::outputAvailable() const
{
/// We don't produce any output
return 0;
}
void ConstantIntegerEncoder::outputRead( char * /*dest*/, const size_t byteCount )
{
/// Should never request any output data
if ( byteCount > 0 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "byteCount=" + toString( byteCount ) );
}
}
void ConstantIntegerEncoder::outputClear()
{
}
void ConstantIntegerEncoder::sourceBufferSetNew( std::vector<SourceDestBuffer> &sbufs )
{
/// Verify that this encoder only has single input buffer
if ( sbufs.size() != 1 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "sbufsSize=" + toString( sbufs.size() ) );
}
sourceBuffer_ = sbufs.at( 0 ).impl();
}
size_t ConstantIntegerEncoder::outputGetMaxSize()
{
/// We don't produce any output
return ( 0 );
}
void ConstantIntegerEncoder::outputSetMaxSize( unsigned /*byteCount*/ )
{
/// Ignore, since don't produce any output
}
#ifdef E57_DEBUG
void ConstantIntegerEncoder::dump( int indent, std::ostream &os ) const
{
Encoder::dump( indent, os );
os << space( indent ) << "currentRecordIndex: " << currentRecordIndex_ << std::endl;
os << space( indent ) << "minimum: " << minimum_ << std::endl;
os << space( indent ) << "sourceBuffer:" << std::endl;
sourceBuffer_->dump( indent + 4, os );
}
#endif

View File

@@ -1,197 +0,0 @@
/*
* 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 "Common.h"
namespace e57
{
class Encoder
{
public:
static std::shared_ptr<Encoder> EncoderFactory( unsigned bytestreamNumber,
std::shared_ptr<CompressedVectorNodeImpl> cVector,
std::vector<SourceDestBuffer> &sbuf, ustring &codecPath );
virtual ~Encoder() = default;
virtual uint64_t processRecords( size_t recordCount ) = 0;
virtual unsigned sourceBufferNextIndex() = 0;
virtual uint64_t currentRecordIndex() = 0;
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 void outputClear() = 0;
virtual void sourceBufferSetNew( std::vector<SourceDestBuffer> &sbufs ) = 0;
virtual size_t outputGetMaxSize() = 0;
virtual void outputSetMaxSize( unsigned byteCount ) = 0;
unsigned bytestreamNumber() const
{
return bytestreamNumber_;
}
#ifdef E57_DEBUG
virtual void dump( int indent = 0, std::ostream &os = std::cout ) const;
#endif
protected:
Encoder( unsigned bytestreamNumber );
unsigned bytestreamNumber_;
};
class BitpackEncoder : public Encoder
{
public:
uint64_t processRecords( size_t recordCount ) override = 0;
unsigned sourceBufferNextIndex() override;
uint64_t currentRecordIndex() override;
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
void outputClear() override;
void sourceBufferSetNew( std::vector<SourceDestBuffer> &sbufs ) override;
size_t outputGetMaxSize() override;
void outputSetMaxSize( unsigned byteCount ) override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
protected:
BitpackEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf, unsigned outputMaxSize,
unsigned alignmentSize );
void outBufferShiftDown();
std::shared_ptr<SourceDestBufferImpl> sourceBuffer_;
std::vector<char> outBuffer_;
size_t outBufferFirst_;
size_t outBufferEnd_;
size_t outBufferAlignmentSize_;
uint64_t currentRecordIndex_;
};
class BitpackFloatEncoder : public BitpackEncoder
{
public:
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
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
protected:
FloatPrecision precision_;
};
class BitpackStringEncoder : public BitpackEncoder
{
public:
BitpackStringEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf, unsigned outputMaxSize );
uint64_t processRecords( size_t recordCount ) override;
bool registerFlushToOutput() override;
float bitsPerRecord() override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
protected:
uint64_t totalBytesProcessed_;
bool isStringActive_;
bool prefixComplete_;
ustring currentString_;
size_t currentCharPosition_;
};
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 );
uint64_t processRecords( size_t recordCount ) override;
bool registerFlushToOutput() override;
float bitsPerRecord() override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
protected:
bool isScaledInteger_;
int64_t minimum_;
int64_t maximum_;
double scale_;
double offset_;
unsigned bitsPerRecord_;
uint64_t sourceBitMask_;
unsigned registerBitsUsed_;
RegisterT register_;
};
class ConstantIntegerEncoder : public Encoder
{
public:
ConstantIntegerEncoder( unsigned bytestreamNumber, SourceDestBuffer &sbuf, int64_t minimum );
uint64_t processRecords( size_t recordCount ) override;
unsigned sourceBufferNextIndex() override;
uint64_t currentRecordIndex() override;
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
void outputClear() override;
void sourceBufferSetNew( std::vector<SourceDestBuffer> &sbufs ) override;
size_t outputGetMaxSize() override;
void outputSetMaxSize( unsigned byteCount ) override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
protected:
std::shared_ptr<SourceDestBufferImpl> sourceBuffer_;
uint64_t currentRecordIndex_;
int64_t minimum_;
};
}

View File

@@ -1,242 +0,0 @@
/*
* 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.
*/
#include "FloatNodeImpl.h"
#include "CheckedFile.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 )
{
// 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 )
{
if ( minimum_ < E57_FLOAT_MIN )
{
minimum_ = E57_FLOAT_MIN;
}
if ( maximum_ > E57_FLOAT_MAX )
{
maximum_ = E57_FLOAT_MAX;
}
}
/// Enforce the given bounds on raw value
if ( value < minimum || maximum < value )
{
throw E57_EXCEPTION2( E57_ERROR_VALUE_OUT_OF_BOUNDS,
"this->pathName=" + this->pathName() + " value=" + toString( value ) +
" minimum=" + toString( minimum ) + " maximum=" + toString( maximum ) );
}
}
bool FloatNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
{
// don't checkImageFileOpen
/// Same node type?
if ( ni->type() != E57_FLOAT )
{
return ( false );
}
/// Downcast to shared_ptr<FloatNodeImpl>
std::shared_ptr<FloatNodeImpl> fi( std::static_pointer_cast<FloatNodeImpl>( ni ) );
/// precision must match
if ( precision_ != fi->precision_ )
{
return ( false );
}
/// minimum must match
if ( minimum_ != fi->minimum_ )
{
return ( false );
}
/// maximum must match
if ( maximum_ != fi->maximum_ )
{
return ( false );
}
/// ignore value_, doesn't have to match
/// Types match
return ( true );
}
bool FloatNodeImpl::isDefined( const ustring &pathName )
{
// don't checkImageFileOpen
/// We have no sub-structure, so if path not empty return false
return pathName.empty();
}
double FloatNodeImpl::value() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return value_;
}
FloatPrecision FloatNodeImpl::precision() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return precision_;
}
double FloatNodeImpl::minimum() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return minimum_;
}
double FloatNodeImpl::maximum() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return maximum_;
}
void FloatNodeImpl::checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin )
{
// don't checkImageFileOpen
/// 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() );
}
}
void FloatNodeImpl::writeXml( ImageFileImplSharedPtr /*imf*/, CheckedFile &cf, int indent,
const char *forcedFieldName )
{
// don't checkImageFileOpen
ustring fieldName;
if ( forcedFieldName )
{
fieldName = forcedFieldName;
}
else
{
fieldName = elementName_;
}
cf << space( indent ) << "<" << fieldName << " type=\"Float\"";
if ( precision_ == E57_SINGLE )
{
cf << " precision=\"single\"";
/// Don't need to write if are default values
if ( minimum_ > E57_FLOAT_MIN )
{
cf << " minimum=\"" << static_cast<float>( minimum_ ) << "\"";
}
if ( maximum_ < E57_FLOAT_MAX )
{
cf << " maximum=\"" << static_cast<float>( maximum_ ) << "\"";
}
/// Write value as child text, unless it is the default value
if ( value_ != 0.0 )
{
cf << ">" << static_cast<float>( value_ ) << "</" << fieldName << ">\n";
}
else
{
cf << "/>\n";
}
}
else
{
/// 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 )
{
cf << " minimum=\"" << minimum_ << "\"";
}
if ( maximum_ < E57_DOUBLE_MAX )
{
cf << " maximum=\"" << maximum_ << "\"";
}
/// Write value as child text, unless it is the default value
if ( value_ != 0.0 )
{
cf << ">" << value_ << "</" << fieldName << ">\n";
}
else
{
cf << "/>\n";
}
}
}
#ifdef E57_DEBUG
void FloatNodeImpl::dump( int indent, std::ostream &os ) const
{
// don't checkImageFileOpen
os << space( indent ) << "type: Float"
<< " (" << type() << ")" << std::endl;
NodeImpl::dump( indent, os );
os << space( indent ) << "precision: ";
if ( precision() == E57_SINGLE )
{
os << "single" << std::endl;
}
else
{
os << "double" << std::endl;
}
/// 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 ) << "minimum: " << minimum_ << std::endl;
os << space( indent ) << "maximum: " << maximum_ << std::endl;
/// Restore old stream config
os.precision( oldPrecision );
os.flags( oldFlags );
}
#endif
}

View File

@@ -1,67 +0,0 @@
#pragma once
/*
* 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.
*/
#include "NodeImpl.h"
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() override = default;
NodeType type() const override
{
return E57_FLOAT;
}
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
bool isDefined( const ustring &pathName ) override;
double value() const;
FloatPrecision precision() const;
double minimum() const;
double maximum() const;
void checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin ) override;
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
const char *forcedFieldName = nullptr ) override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
private:
double value_;
FloatPrecision precision_;
double minimum_;
double maximum_;
};
}

View File

@@ -1,945 +0,0 @@
/*
* 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.
*/
#include "ImageFileImpl.h"
#include "CheckedFile.h"
#include "E57Version.h"
#include "E57XmlParser.h"
#include "StructureNodeImpl.h"
namespace e57
{
struct NameSpace
{
ustring prefix;
ustring uri;
NameSpace( const ustring &prefix0, const ustring &uri0 ) : prefix( prefix0 ), uri( uri0 )
{
}
};
struct E57FileHeader
{
char fileSignature[8] = {};
uint32_t majorVersion = 0;
uint32_t minorVersion = 0;
uint64_t filePhysicalLength = 0;
uint64_t xmlPhysicalOffset = 0;
uint64_t xmlLogicalLength = 0;
uint64_t pageSize = 0;
// char e57LibraryVersion[8]; //Not in V1.0 Standard
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const;
#endif
};
#ifdef E57_DEBUG
void E57FileHeader::dump( int indent, std::ostream &os ) const
{
os << space( indent ) << "fileSignature: ";
os.write( fileSignature, sizeof( fileSignature ) );
os << std::endl;
os << space( indent ) << "majorVersion: " << majorVersion << std::endl;
os << space( indent ) << "minorVersion: " << minorVersion << std::endl;
os << space( indent ) << "filePhysicalLength: " << filePhysicalLength << std::endl;
os << space( indent ) << "xmlPhysicalOffset: " << xmlPhysicalOffset << std::endl;
os << space( indent ) << "xmlLogicalLength: " << xmlLogicalLength << std::endl;
os << space( indent ) << "pageSize: " << pageSize << std::endl;
}
#endif
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 )
{
/// 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.
#ifdef E57_MAX_VERBOSE
std::cout << "ImageFileImpl() called, fileName=" << fileName << " mode=" << mode << std::endl;
#endif
unusedLogicalStart_ = sizeof( E57FileHeader );
fileName_ = fileName;
/// Get shared_ptr to this object
ImageFileImplSharedPtr imf = shared_from_this();
// Accept "w" or "r" modes
isWriter_ = ( mode == "w" );
if ( !isWriter_ && ( mode != "r" ) )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_API_ARGUMENT, "mode=" + ustring( mode ) );
}
file_ = nullptr;
// Writing
if ( isWriter_ )
{
try
{
/// Open file for writing, truncate if already exists.
file_ = new CheckedFile( fileName_, CheckedFile::WriteCreate, checksumPolicy );
std::shared_ptr<StructureNodeImpl> root( new StructureNodeImpl( imf ) );
root_ = root;
root_->setAttachedRecursive();
unusedLogicalStart_ = sizeof( E57FileHeader );
xmlLogicalOffset_ = 0;
xmlLogicalLength_ = 0;
}
catch ( ... )
{
delete file_;
file_ = nullptr;
throw;
}
return;
}
// Reading
try
{
/// Open file for reading.
file_ = new CheckedFile( fileName_, CheckedFile::ReadOnly, checksumPolicy );
std::shared_ptr<StructureNodeImpl> root( new StructureNodeImpl( imf ) );
root_ = root;
root_->setAttachedRecursive();
E57FileHeader header;
readFileHeader( file_, header );
xmlLogicalOffset_ = file_->physicalToLogical( header.xmlPhysicalOffset );
xmlLogicalLength_ = header.xmlLogicalLength;
}
catch ( ... )
{
delete file_;
file_ = nullptr;
throw;
}
try
{
/// 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).
E57XmlFileInputSource xmlSection( file_, xmlLogicalOffset_, xmlLogicalLength_ );
unusedLogicalStart_ = sizeof( E57FileHeader );
/// Do the parse, building up the node tree
parser.parse( xmlSection );
}
catch ( ... )
{
delete file_;
file_ = nullptr;
throw;
}
}
void ImageFileImpl::construct2( const char *input, const uint64_t size )
{
/// Second phase of construction, now we have a well-formed ImageFile object.
#ifdef E57_MAX_VERBOSE
std::cout << "ImageFileImpl() called, fileName=<StreamBuffer> mode=r" << std::endl;
#endif
unusedLogicalStart_ = sizeof( E57FileHeader );
fileName_ = "<StreamBuffer>";
/// Get shared_ptr to this object
ImageFileImplSharedPtr imf = shared_from_this();
isWriter_ = false;
file_ = nullptr;
try
{
/// Open file for reading.
file_ = new CheckedFile( input, size, checksumPolicy );
std::shared_ptr<StructureNodeImpl> root( new StructureNodeImpl( imf ) );
root_ = root;
root_->setAttachedRecursive();
E57FileHeader header;
readFileHeader( file_, header );
xmlLogicalOffset_ = file_->physicalToLogical( header.xmlPhysicalOffset );
xmlLogicalLength_ = header.xmlLogicalLength;
}
catch ( ... )
{
delete file_;
file_ = nullptr;
throw;
}
try
{
/// 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).
E57XmlFileInputSource xmlSection( file_, xmlLogicalOffset_, xmlLogicalLength_ );
unusedLogicalStart_ = sizeof( E57FileHeader );
/// Do the parse, building up the node tree
parser.parse( xmlSection );
}
catch ( ... )
{
delete file_;
file_ = nullptr;
throw;
}
}
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__ ) );
return root_;
}
void ImageFileImpl::close()
{
/// If file already closed, have nothing to do
if ( !file_ )
{
return;
}
if ( isWriter_ )
{
/// 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
while ( ( file_->position( CheckedFile::Logical ) - xmlLogicalOffset_ ) % 4 != 0 )
{
*file_ << " ";
}
/// Note logical length
xmlLogicalLength_ = file_->position( CheckedFile::Logical ) - xmlLogicalOffset_;
/// Init header contents
E57FileHeader header;
memcpy( &header.fileSignature, "ASTM-E57", 8 );
header.majorVersion = E57_FORMAT_MAJOR;
header.minorVersion = E57_FORMAT_MINOR;
header.filePhysicalLength = file_->length( CheckedFile::Physical );
header.xmlPhysicalOffset = xmlPhysicalOffset;
header.xmlLogicalLength = xmlLogicalLength_;
header.pageSize = CheckedFile::physicalPageSize;
#ifdef E57_MAX_VERBOSE
header.dump();
#endif
/// Write header at beginning of file
file_->seek( 0 );
file_->write( reinterpret_cast<char *>( &header ), sizeof( header ) );
file_->close();
}
delete file_;
file_ = nullptr;
}
void ImageFileImpl::cancel()
{
/// If file already closed, have nothing to do
if ( !file_ )
{
return;
}
/// Close the file and ulink (delete) it.
/// It is legal to cancel a read file, but file isn't deleted.
if ( isWriter_ )
{
file_->unlink();
}
else
{
file_->close();
}
delete file_;
file_ = nullptr;
}
bool ImageFileImpl::isOpen() const
{
return ( file_ != nullptr );
}
bool ImageFileImpl::isWriter() const
{
return isWriter_;
}
int ImageFileImpl::writerCount() const
{
return writerCount_;
}
int ImageFileImpl::readerCount() const
{
return readerCount_;
}
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
{
cancel();
}
catch ( ... )
{
};
/// Just in case cancel failed without freeing file_, do free here.
delete file_;
file_ = nullptr;
}
uint64_t ImageFileImpl::allocateSpace( uint64_t byteCount, bool doExtendNow )
{
uint64_t oldLogicalStart = unusedLogicalStart_;
/// 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 ( doExtendNow )
{
file_->extend( unusedLogicalStart_ );
}
return oldLogicalStart;
}
CheckedFile *ImageFileImpl::file() const
{
return file_;
}
ustring ImageFileImpl::fileName() const
{
// don't checkImageFileOpen, since need to get fileName to report not open
return fileName_;
}
void ImageFileImpl::extensionsAdd( const ustring &prefix, const ustring &uri )
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
//??? 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.
ustring dummy;
if ( extensionsLookupPrefix( prefix, dummy ) )
{
throw E57_EXCEPTION2( E57_ERROR_DUPLICATE_NAMESPACE_PREFIX, "prefix=" + prefix + " uri=" + uri );
}
if ( extensionsLookupUri( uri, dummy ) )
{
throw E57_EXCEPTION2( E57_ERROR_DUPLICATE_NAMESPACE_URI, "prefix=" + prefix + " uri=" + uri );
;
}
/// Append at end of list
nameSpaces_.emplace_back( prefix, uri );
}
bool ImageFileImpl::extensionsLookupPrefix( const ustring &prefix, ustring &uri ) const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
/// Linear search for matching prefix
std::vector<NameSpace>::const_iterator it;
for ( it = nameSpaces_.begin(); it < nameSpaces_.end(); ++it )
{
if ( it->prefix == prefix )
{
uri = it->uri;
return true;
}
}
return false;
}
bool ImageFileImpl::extensionsLookupUri( const ustring &uri, ustring &prefix ) const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
/// Linear search for matching URI
std::vector<NameSpace>::const_iterator it;
for ( it = nameSpaces_.begin(); it < nameSpaces_.end(); ++it )
{
if ( it->uri == uri )
{
prefix = it->prefix;
return true;
}
}
return false;
}
size_t ImageFileImpl::extensionsCount() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return nameSpaces_.size();
}
ustring ImageFileImpl::extensionsPrefix( const size_t index ) const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return nameSpaces_[index].prefix; //??? throw e57 exception here if out of bounds?
}
ustring ImageFileImpl::extensionsUri( const size_t index ) const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return nameSpaces_[index].uri; //??? throw e57 exception here if out of bounds?
}
bool ImageFileImpl::isElementNameExtended( const ustring &elementName )
{
/// don't checkImageFileOpen
/// Make sure doesn't have any "/" in it
size_t found = elementName.find_first_of( '/' );
if ( found != std::string::npos )
{
return false;
}
ustring prefix, localPart;
try
{
/// Throws if elementName bad
elementNameParse( elementName, prefix, localPart );
}
catch ( E57Exception & /*ex*/ )
{
return false;
}
/// 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
// cout << "isElementNameLegal elementName=""" << elementName << """" <<
// std::endl;
#endif
try
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
/// Throws if elementName bad
checkElementNameLegal( elementName, allowNumber );
}
catch ( E57Exception & /*ex*/ )
{
return false;
}
/// If get here, the name was good
return true;
}
bool ImageFileImpl::isPathNameLegal( const ustring &pathName )
{
#ifdef E57_MAX_VERBOSE
// cout << "isPathNameLegal elementName=""" << pathName << """" << std::endl;
#endif
try
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
/// Throws if pathName bad
pathNameCheckWellFormed( pathName );
}
catch ( E57Exception & /*ex*/ )
{
return false;
}
/// If get here, the name was good
return true;
}
void ImageFileImpl::checkElementNameLegal( const ustring &elementName, bool allowNumber )
{
/// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
ustring prefix;
ustring localPart;
/// Throws if bad elementName
elementNameParse( elementName, prefix, localPart, allowNumber );
/// 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;
}
}
void ImageFileImpl::pathNameCheckWellFormed( const ustring &pathName )
{
/// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
/// 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 )
{
#ifdef E57_MAX_VERBOSE
std::cout << "pathNameParse pathname="
""
<< pathName
<< ""
""
<< std::endl;
#endif
/// no checkImageFileOpen(__FILE__, __LINE__, __FUNCTION__)
/// Clear previous contents of fields vector
fields.clear();
size_t start = 0;
/// Check if absolute path
if ( pathName[start] == '/' )
{
isRelative = false;
start = 1;
}
else
{
isRelative = true;
}
/// 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
ustring elementName = pathName.substr( start, slash - start );
if ( !isElementNameLegal( elementName ) )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "pathName=" + pathName + " elementName=" + elementName );
}
/// Add to list
fields.push_back( elementName );
if ( slash == std::string::npos )
{
break;
}
/// 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
start = slash + 1;
}
/// Empty relative path is not allowed
if ( isRelative && fields.empty() )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "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++ )
{
std::cout << fields[i] << ",";
}
std::cout << std::endl;
#endif
}
ustring ImageFileImpl::pathNameUnparse( bool isRelative, const std::vector<ustring> &fields )
{
ustring path;
if ( !isRelative )
{
path.push_back( '/' );
}
for ( unsigned i = 0; i < fields.size(); ++i )
{
path.append( fields.at( i ) );
if ( i < fields.size() - 1 )
{
path.push_back( '/' );
}
}
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?
uint64_t stateCountMinus1 = maximum - minimum;
unsigned log2 = 0;
if ( stateCountMinus1 & 0xFFFFFFFF00000000LL )
{
stateCountMinus1 >>= 32;
log2 += 32;
}
if ( stateCountMinus1 & 0xFFFF0000LL )
{
stateCountMinus1 >>= 16;
log2 += 16;
}
if ( stateCountMinus1 & 0xFF00LL )
{
stateCountMinus1 >>= 8;
log2 += 8;
}
if ( stateCountMinus1 & 0xF0LL )
{
stateCountMinus1 >>= 4;
log2 += 4;
}
if ( stateCountMinus1 & 0xCLL )
{
stateCountMinus1 >>= 2;
log2 += 2;
}
if ( stateCountMinus1 & 0x2LL )
{
stateCountMinus1 >>= 1;
log2 += 1;
}
if ( stateCountMinus1 & 1LL )
{
log2++;
}
return log2;
}
}

View File

@@ -1,124 +0,0 @@
/*
* 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 <memory>
#include "Common.h"
namespace e57
{
class CheckedFile;
struct E57FileHeader;
struct NameSpace;
class ImageFileImpl : public std::enable_shared_from_this<ImageFileImpl>
{
public:
ImageFileImpl( ReadChecksumPolicy policy );
void construct2( const ustring &fileName, const ustring &mode );
void construct2( const char *input, const uint64_t size );
std::shared_ptr<StructureNodeImpl> root();
void close();
void cancel();
bool isOpen() const;
bool isWriter() const;
int writerCount() const;
int readerCount() const;
~ImageFileImpl();
uint64_t allocateSpace( uint64_t byteCount, bool doExtendNow );
CheckedFile *file() const;
ustring fileName() const;
/// Manipulate registered extensions in the file
void extensionsAdd( const ustring &prefix, const ustring &uri );
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;
/// 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
void dump( int indent = 0, std::ostream &os = std::cout ) const;
#endif
private:
friend class E57XmlParser;
friend class BlobNodeImpl;
friend class CompressedVectorWriterImpl;
friend class CompressedVectorReaderImpl; //??? add file() instead of
// accessing file_, others
// friends too
static void readFileHeader( CheckedFile *file, E57FileHeader &header );
void checkImageFileOpen( const char *srcFileName, int srcLineNumber, const char *srcFunctionName ) const;
ustring fileName_;
bool isWriter_;
int writerCount_;
int readerCount_;
ReadChecksumPolicy checksumPolicy;
CheckedFile *file_;
/// Read file attributes
uint64_t xmlLogicalOffset_;
uint64_t xmlLogicalLength_;
/// Write file attributes
uint64_t unusedLogicalStart_;
/// Bidirectional map from namespace prefix to uri
std::vector<NameSpace> nameSpaces_;
/// Smart pointer to metadata tree
std::shared_ptr<StructureNodeImpl> root_;
};
}

View File

@@ -1,167 +0,0 @@
/*
* 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.
*/
#include "IntegerNodeImpl.h"
#include "CheckedFile.h"
namespace e57
{
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 E57_EXCEPTION2( E57_ERROR_VALUE_OUT_OF_BOUNDS,
"this->pathName=" + this->pathName() + " value=" + toString( value ) +
" minimum=" + toString( minimum ) + " maximum=" + toString( maximum ) );
}
}
bool IntegerNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
{
// don't checkImageFileOpen
/// Same node type?
if ( ni->type() != E57_INTEGER )
{
return ( false );
}
/// Downcast to shared_ptr<IntegerNodeImpl>
std::shared_ptr<IntegerNodeImpl> ii( std::static_pointer_cast<IntegerNodeImpl>( ni ) );
/// minimum must match
if ( minimum_ != ii->minimum_ )
{
return ( false );
}
/// maximum must match
if ( maximum_ != ii->maximum_ )
{
return ( false );
}
/// ignore value_, doesn't have to match
/// Types match
return ( true );
}
bool IntegerNodeImpl::isDefined( const ustring &pathName )
{
// don't checkImageFileOpen
/// We have no sub-structure, so if path not empty return false
return pathName.empty();
}
int64_t IntegerNodeImpl::value()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( value_ );
}
int64_t IntegerNodeImpl::minimum()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( minimum_ );
}
int64_t IntegerNodeImpl::maximum()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( maximum_ );
}
void IntegerNodeImpl::checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin )
{
// don't checkImageFileOpen
/// 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() );
}
}
void IntegerNodeImpl::writeXml( ImageFileImplSharedPtr /*imf???*/, CheckedFile &cf, int indent,
const char *forcedFieldName )
{
// don't checkImageFileOpen
ustring fieldName;
if ( forcedFieldName )
{
fieldName = forcedFieldName;
}
else
{
fieldName = elementName_;
}
cf << space( indent ) << "<" << fieldName << " type=\"Integer\"";
/// Don't need to write if are default values
if ( minimum_ != E57_INT64_MIN )
{
cf << " minimum=\"" << minimum_ << "\"";
}
if ( maximum_ != E57_INT64_MAX )
{
cf << " maximum=\"" << maximum_ << "\"";
}
/// Write value as child text, unless it is the default value
if ( value_ != 0 )
{
cf << ">" << value_ << "</" << fieldName << ">\n";
}
else
{
cf << "/>\n";
}
}
#ifdef E57_DEBUG
void IntegerNodeImpl::dump( int indent, std::ostream &os ) const
{
// don't checkImageFileOpen
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;
os << space( indent ) << "maximum: " << maximum_ << std::endl;
}
#endif
}

View File

@@ -1,65 +0,0 @@
#pragma once
/*
* 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.
*/
#include "NodeImpl.h"
namespace e57
{
class IntegerNodeImpl : public NodeImpl
{
public:
IntegerNodeImpl( ImageFileImplWeakPtr destImageFile, int64_t value = 0, int64_t minimum = 0,
int64_t maximum = 0 );
~IntegerNodeImpl() override = default;
NodeType type() const override
{
return E57_INTEGER;
}
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
bool isDefined( const ustring &pathName ) override;
int64_t value();
int64_t minimum();
int64_t maximum();
void checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin ) override;
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
const char *forcedFieldName = nullptr ) override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
private:
int64_t value_;
int64_t minimum_;
int64_t maximum_;
};
}

View File

@@ -1,431 +0,0 @@
/*
* 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.
*/
#include "NodeImpl.h"
#include "ImageFileImpl.h"
#include "SourceDestBufferImpl.h"
#include "VectorNodeImpl.h"
using namespace e57;
NodeImpl::NodeImpl( ImageFileImplWeakPtr destImageFile ) : destImageFile_( destImageFile ), isAttached_( false )
{
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
{
/// 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 );
}
}
bool NodeImpl::isRoot() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return parent_.expired();
};
NodeImplSharedPtr NodeImpl::parent()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
if ( isRoot() )
{
/// If is root, then has self as parent (by convention)
return shared_from_this();
}
NodeImplSharedPtr myParent( parent_ );
return myParent;
}
ustring NodeImpl::pathName() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
if ( isRoot() )
{
return ( "/" );
}
NodeImplSharedPtr p( parent_ );
if ( p->isRoot() )
{
return ( "/" + elementName_ );
}
return ( p->pathName() + "/" + elementName_ );
}
ustring NodeImpl::relativePathName( const NodeImplSharedPtr &origin, ustring childPathName ) const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
if ( origin == shared_from_this() )
{
return ( childPathName );
}
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 );
}
/// Assemble relativePathName from right to left, recursively
NodeImplSharedPtr p( parent_ );
if ( childPathName.empty() )
{
return p->relativePathName( origin, elementName_ );
}
return p->relativePathName( origin, elementName_ + "/" + childPathName );
}
ustring NodeImpl::elementName() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return elementName_;
}
ImageFileImplSharedPtr NodeImpl::destImageFile()
{
/// don't checkImageFileOpen
return ImageFileImplSharedPtr( destImageFile_ );
}
bool NodeImpl::isAttached() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return isAttached_;
}
void NodeImpl::setAttachedRecursive()
{
/// 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
ImageFileImplSharedPtr imf( destImageFile_ );
return imf->fileName();
}
void NodeImpl::setParent( NodeImplSharedPtr parent, const ustring &elementName )
{
/// 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?
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() );
}
parent_ = parent;
elementName_ = elementName;
/// If parent is attached then we are attached (and all of our children)
if ( parent->isAttached() )
{
setAttachedRecursive();
}
}
NodeImplSharedPtr NodeImpl::getRoot()
{
/// don't checkImageFileOpen
NodeImplSharedPtr p( shared_from_this() );
while ( !p->isRoot() )
{
p = NodeImplSharedPtr( p->parent_ ); //??? check if bad ptr?
}
return p;
}
//??? 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
NodeImplSharedPtr p( shared_from_this() );
while ( !p->isRoot() )
{
/// We have a parent since we are not root
p = NodeImplSharedPtr( p->parent_ ); //??? check if bad ptr?
switch ( p->type() )
{
case E57_VECTOR:
{
/// 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 ( !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
return ( true );
default:
break;
}
}
/// 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.
#ifdef E57_DEBUG
_verifyPathNameAbsolute( pathName );
#endif
NodeImplSharedPtr root = _verifyAndGetRoot();
/// 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.
#ifdef E57_DEBUG
_verifyPathNameAbsolute( pathName );
#endif
NodeImplSharedPtr root = _verifyAndGetRoot();
/// 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 ); //???
}
void NodeImpl::checkBuffers( const std::vector<SourceDestBuffer> &sdbufs,
bool allowMissing ) //??? convert sdbufs to vector of shared_ptr
{
/// this node is prototype of CompressedVector
/// don't checkImageFileOpen
StringSet pathNames;
for ( unsigned i = 0; i < sdbufs.size(); i++ )
{
ustring pathName = sdbufs.at( i ).impl()->pathName();
/// 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() ) );
}
/// 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 );
}
/// Check no bad fields in sdbufs
if ( !isDefined( pathName ) )
{
throw E57_EXCEPTION2( E57_ERROR_PATH_UNDEFINED,
"this->pathName=" + this->pathName() + " sdbuf.pathName=" + pathName );
}
}
if ( !allowMissing )
{
/// 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
if ( this == &*target ) //??? ok?
{
return true;
}
switch ( type() )
{
case E57_STRUCTURE:
{
auto sni = static_cast<StructureNodeImpl *>( this );
/// Recursively visit child nodes
int64_t childCount = sni->childCount();
for ( int64_t i = 0; i < childCount; ++i )
{
if ( sni->get( i )->findTerminalPosition( target, countFromLeft ) )
{
return true;
}
}
}
break;
case E57_VECTOR:
{
auto vni = static_cast<VectorNodeImpl *>( this );
/// Recursively visit child nodes
int64_t childCount = vni->childCount();
for ( int64_t i = 0; i < childCount; ++i )
{
if ( vni->get( i )->findTerminalPosition( target, countFromLeft ) )
{
return true;
}
}
}
break;
case E57_COMPRESSED_VECTOR:
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:
countFromLeft++;
break;
}
return ( false );
}
#ifdef E57_DEBUG
void NodeImpl::dump( int indent, std::ostream &os ) const
{
/// don't checkImageFileOpen
os << space( indent ) << "elementName: " << elementName_ << std::endl;
os << space( indent ) << "isAttached: " << isAttached_ << std::endl;
os << space( indent ) << "path: " << pathName() << std::endl;
}
bool NodeImpl::_verifyPathNameAbsolute( const ustring &inPathName )
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
/// Parse to determine if pathName is absolute
bool isRelative = false;
std::vector<ustring> fields;
ImageFileImplSharedPtr imf( destImageFile_ );
imf->pathNameParse( inPathName, isRelative,
fields ); // throws if bad pathName
/// If not an absolute path name, have error
if ( isRelative )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_PATH_NAME, "this->pathName=" + this->pathName() + " pathName=" + inPathName );
}
return isRelative;
}
#endif
NodeImplSharedPtr NodeImpl::_verifyAndGetRoot()
{
/// 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).
switch ( root->type() )
{
case E57_STRUCTURE:
case E57_VECTOR: //??? COMPRESSED_VECTOR?
break;
default:
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "root invalid for this->pathName=" + this->pathName() );
}
return root;
}

View File

@@ -1,101 +0,0 @@
/*
* 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 "Common.h"
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;
virtual bool isTypeEquivalent( NodeImplSharedPtr ni ) = 0;
bool isRoot() const;
NodeImplSharedPtr parent();
ustring pathName() const;
ustring relativePathName( const NodeImplSharedPtr &origin, ustring childPathName = ustring() ) const;
ustring elementName() const;
ImageFileImplSharedPtr destImageFile();
ustring imageFileName() const;
virtual bool isDefined( const ustring &pathName ) = 0;
bool isAttached() const;
virtual void setAttachedRecursive();
void setParent( NodeImplSharedPtr parent, const ustring &elementName );
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 checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin ) = 0;
void checkBuffers( const std::vector<SourceDestBuffer> &sdbufs, bool allowMissing );
bool findTerminalPosition( const NodeImplSharedPtr &target, uint64_t &countFromLeft );
virtual void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
const char *forcedFieldName = nullptr ) = 0;
virtual ~NodeImpl() = default;
#ifdef E57_DEBUG
virtual void dump( int indent = 0, std::ostream &os = std::cout ) const;
#endif
private:
#ifdef E57_DEBUG
bool _verifyPathNameAbsolute( const ustring &inPathName );
#endif
NodeImplSharedPtr _verifyAndGetRoot();
protected:
friend class StructureNodeImpl;
friend class CompressedVectorWriterImpl;
friend class Decoder;
friend class Encoder;
NodeImpl( ImageFileImplWeakPtr destImageFile );
NodeImpl &operator=( NodeImpl &n );
virtual NodeImplSharedPtr lookup( const ustring & /*pathName*/ )
{
return NodeImplSharedPtr();
}
NodeImplSharedPtr getRoot();
ImageFileImplWeakPtr destImageFile_;
NodeImplWeakPtr parent_;
ustring elementName_;
bool isAttached_;
};
}

View File

@@ -1,734 +0,0 @@
/*
* 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.
*/
#include <cstring>
#include "CheckedFile.h"
#include "Packet.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;
uint8_t reserved1 = 0; // must be zero
uint16_t packetLogicalLengthMinus1 = 0;
void verify( unsigned bufferLength = 0 ) const; //???use
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const;
#endif
};
//=============================================================================
// PacketReadCache
PacketReadCache::PacketReadCache( CheckedFile *cFile, unsigned packetCount ) : cFile_( cFile ), entries_( packetCount )
{
if ( packetCount == 0 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "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;
#endif
/// Only allow one locked packet at a time.
if ( lockCount_ > 0 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "lockCount=" + toString( lockCount_ ) );
}
/// Offset can't be 0
if ( packetLogicalOffset == 0 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetLogicalOffset=" + toString( packetLogicalOffset ) );
}
/// 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
std::cout << " Found matching cache entry, index=" << i << std::endl;
#endif
/// Mark entry with current useCount (keeps track of age of entry).
entry.lastUsed_ = ++useCount_;
/// Publish buffer address to caller
pkt = entry.buffer_;
/// 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
++lockCount_;
return plock;
}
}
/// Get here if didn't find a match already in cache.
/// Find least recently used (LRU) packet buffer
unsigned oldestEntry = 0;
unsigned oldestUsed = entries_.at( 0 ).lastUsed_;
for ( unsigned i = 0; i < entries_.size(); ++i )
{
const auto &entry = entries_[i];
if ( entry.lastUsed_ < oldestUsed )
{
oldestEntry = i;
oldestUsed = entry.lastUsed_;
}
}
#ifdef E57_MAX_VERBOSE
std::cout << " Oldest entry=" << oldestEntry << " lastUsed=" << oldestUsed << std::endl;
#endif
readPacket( oldestEntry, packetLogicalOffset );
/// Publish buffer address to caller
pkt = entries_[oldestEntry].buffer_;
/// 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
++lockCount_;
return plock;
}
void PacketReadCache::unlock( unsigned cacheIndex )
{
(void)cacheIndex;
//??? why lockedEntry not used?
#ifdef E57_MAX_VERBOSE
std::cout << "PacketReadCache::unlock() called, cacheIndex=" << cacheIndex << std::endl;
#endif
if ( lockCount_ != 1 )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "lockCount=" + toString( lockCount_ ) );
}
--lockCount_;
}
void PacketReadCache::readPacket( unsigned oldestEntry, uint64_t packetLogicalOffset )
{
#ifdef E57_MAX_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.
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.
unsigned packetLength = header.packetLogicalLengthMinus1 + 1;
/// Be paranoid about packetLength before read
if ( packetLength > DATA_PACKET_MAX )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
}
auto &entry = entries_.at( oldestEntry );
/// 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.
switch ( header.packetType )
{
case DATA_PACKET:
{
auto dpkt = reinterpret_cast<DataPacket *>( entry.buffer_ );
dpkt->verify( packetLength );
#ifdef E57_MAX_VERBOSE
std::cout << " data packet:" << std::endl;
dpkt->dump( 4 ); //???
#endif
}
break;
case INDEX_PACKET:
{
auto ipkt = reinterpret_cast<IndexPacket *>( entry.buffer_ );
ipkt->verify( packetLength );
#ifdef E57_MAX_VERBOSE
std::cout << " index packet:" << std::endl;
ipkt->dump( 4 ); //???
#endif
}
break;
case EMPTY_PACKET:
{
auto hp = reinterpret_cast<EmptyPacketHeader *>( entry.buffer_ );
hp->verify( packetLength );
#ifdef E57_MAX_VERBOSE
std::cout << " empty packet:" << std::endl;
hp->dump( 4 ); //???
#endif
}
break;
default:
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "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.
entry.lastUsed_ = ++useCount_;
}
#ifdef E57_DEBUG
void PacketReadCache::dump( int indent, std::ostream &os )
{
os << space( indent ) << "lockCount: " << lockCount_ << std::endl;
os << space( indent ) << "useCount: " << useCount_ << std::endl;
os << space( indent ) << "entries:" << std::endl;
for ( unsigned i = 0; i < entries_.size(); i++ )
{
os << space( indent ) << "entry[" << i << "]:" << std::endl;
os << space( indent + 4 ) << "logicalOffset: " << entries_[i].logicalOffset_ << std::endl;
os << space( indent + 4 ) << "lastUsed: " << entries_[i].lastUsed_ << std::endl;
if ( entries_[i].logicalOffset_ != 0 )
{
os << space( indent + 4 ) << "packet:" << std::endl;
switch ( reinterpret_cast<EmptyPacketHeader *>( entries_.at( i ).buffer_ )->packetType )
{
case DATA_PACKET:
{
auto dpkt = reinterpret_cast<DataPacket *>( entries_.at( i ).buffer_ );
dpkt->dump( indent + 6, os );
}
break;
case INDEX_PACKET:
{
auto ipkt = reinterpret_cast<IndexPacket *>( entries_.at( i ).buffer_ );
ipkt->dump( indent + 6, os );
}
break;
case EMPTY_PACKET:
{
auto hp = reinterpret_cast<EmptyPacketHeader *>( entries_.at( i ).buffer_ );
hp->dump( indent + 6, os );
}
break;
default:
throw E57_EXCEPTION2(
E57_ERROR_INTERNAL,
"packetType=" +
toString( reinterpret_cast<EmptyPacketHeader *>( entries_.at( i ).buffer_ )->packetType ) );
}
}
}
}
#endif
//=============================================================================
// PacketLock
PacketLock::PacketLock( PacketReadCache *cache, unsigned cacheIndex ) : cache_( cache ), cacheIndex_( cacheIndex )
{
#ifdef E57_MAX_VERBOSE
std::cout << "PacketLock() called" << std::endl;
#endif
}
PacketLock::~PacketLock()
{
#ifdef E57_MAX_VERBOSE
std::cout << "~PacketLock() called" << std::endl;
#endif
try
{
/// Note cache must live longer than lock, this is reasonable assumption.
cache_->unlock( cacheIndex_ );
}
catch ( ... )
{
//??? report?
}
}
//=============================================================================
// DataPacketHeader
DataPacketHeader::DataPacketHeader()
{
/// Double check that packet struct is correct length. Watch out for RTTI
/// increasing the size.
static_assert( sizeof( DataPacketHeader ) == 6, "Unexpected size of DataPacketHeader" );
}
void DataPacketHeader::reset()
{
packetFlags = 0;
packetLogicalLengthMinus1 = 0;
bytestreamCount = 0;
}
void DataPacketHeader::verify( unsigned bufferLength ) const
{
/// Verify that packet is correct type
if ( packetType != DATA_PACKET )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( packetType ) );
}
/// ??? check reserved flags zero?
/// 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 ) );
}
/// Check packet length is multiple of 4
if ( packetLength % 4 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
}
/// 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 ) );
}
/// Make sure there is at least one entry in packet ??? 0 record cvect
/// allowed?
if ( bytestreamCount == 0 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "bytestreamCount=" + toString( bytestreamCount ) );
}
/// 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 ) );
}
}
#ifdef E57_DEBUG
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 ) << "packetLogicalLengthMinus1: " << packetLogicalLengthMinus1 << std::endl;
os << space( indent ) << "bytestreamCount: " << bytestreamCount << std::endl;
}
#endif
//=============================================================================
// DataPacket
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" );
}
void DataPacket::verify( unsigned bufferLength ) const
{
//??? do all packets need versions? how extend without breaking older
// checking? need to check
// file version#?
/// 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
auto bsbLength = reinterpret_cast<const uint16_t *>( &payload[0] );
unsigned totalStreamByteCount = 0;
for ( unsigned i = 0; i < header.bytestreamCount; i++ )
{
totalStreamByteCount += bsbLength[i];
}
/// Calc size of packet needed
const unsigned packetLength = header.packetLogicalLengthMinus1 + 1;
const unsigned needed = sizeof( DataPacketHeader ) + 2 * header.bytestreamCount + totalStreamByteCount;
#ifdef E57_MAX_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 > packetLength || needed + 3 < packetLength )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
"needed=" + toString( needed ) + "packetLength=" + toString( packetLength ) );
}
/// 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 ) );
}
}
}
char *DataPacket::getBytestream( unsigned bytestreamNumber, unsigned &byteCount )
{
#ifdef E57_MAX_VERBOSE
std::cout << "getBytestream called, bytestreamNumber=" << bytestreamNumber << std::endl;
#endif
/// Verify that packet is correct type
if ( header.packetType != DATA_PACKET )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( header.packetType ) );
}
/// Check bytestreamNumber in bounds
if ( bytestreamNumber >= header.bytestreamCount )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "bytestreamNumber=" + toString( bytestreamNumber ) +
"bytestreamCount=" + toString( header.bytestreamCount ) );
}
/// 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;
for ( unsigned i = 0; i < bytestreamNumber; i++ )
{
totalPreceeding += bsbLength[i];
}
byteCount = bsbLength[bytestreamNumber];
/// Double check buffer is completely within packet
if ( sizeof( DataPacketHeader ) + 2 * header.bytestreamCount + totalPreceeding + byteCount >
header.packetLogicalLengthMinus1 + 1U )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL,
"bytestreamCount=" + toString( header.bytestreamCount ) + " totalPreceeding=" +
toString( totalPreceeding ) + " byteCount=" + toString( byteCount ) +
" packetLogicalLengthMinus1=" + toString( header.packetLogicalLengthMinus1 ) );
}
/// Return start of buffer
return ( &streamBase[totalPreceeding] );
}
unsigned DataPacket::getBytestreamBufferLength( unsigned bytestreamNumber )
{
//??? for now:
unsigned byteCount;
(void)getBytestream( bytestreamNumber, byteCount );
return ( byteCount );
}
#ifdef E57_DEBUG
void DataPacket::dump( int indent, std::ostream &os ) const
{
if ( header.packetType != DATA_PACKET )
{
throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetType=" + toString( header.packetType ) );
}
reinterpret_cast<const DataPacketHeader *>( this )->dump( indent, os );
auto bsbLength = reinterpret_cast<const uint16_t *>( &payload[0] );
auto p = reinterpret_cast<const uint8_t *>( &bsbLength[header.bytestreamCount] );
for ( unsigned i = 0; i < header.bytestreamCount; i++ )
{
os << space( indent ) << "bytestream[" << i << "]:" << std::endl;
os << space( indent + 4 ) << "length: " << bsbLength[i] << std::endl;
/*====
unsigned j;
for (j=0; j < bsbLength[i] && j < 10; j++)
os << space(indent+4) << "byte[" << j << "]=" << (unsigned)p[j]
<< std::endl; if (j < bsbLength[i]) os << space(indent+4) << bsbLength[i]-j << "
more unprinted..." << std::endl;
====*/
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 ) ) );
}
}
}
#endif
//=============================================================================
// IndexPacket
void IndexPacket::verify( unsigned bufferLength, uint64_t totalRecordCount, uint64_t fileSize ) const
{
(void)totalRecordCount; (void)fileSize;
//??? 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 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( packetType ) );
}
/// 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 ) );
}
/// Check packet length is multiple of 4
if ( packetLength % 4 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
}
/// Make sure there is at least one entry in packet ??? 0 record cvect
/// allowed?
if ( entryCount == 0 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "entryCount=" + toString( entryCount ) );
}
/// Have to have <= 2048 entries
if ( entryCount > MAX_ENTRIES )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "entryCount=" + toString( entryCount ) );
}
/// Index level should be <= 5. Because (5+1)* 11 bits = 66 bits, which will
/// cover largest number of chunks possible.
if ( indexLevel > 5 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "indexLevel=" + toString( 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 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
"indexLevel=" + toString( indexLevel ) + " entryCount=" + toString( 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 ( reserved1[i] != 0 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "i=" + toString( i ) );
}
}
/// 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 ) );
}
/// Check if entries will fit in space provided
unsigned neededLength = 16 + 8 * entryCount;
if ( packetLength < neededLength )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET,
"packetLength=" + toString( packetLength ) + " neededLength=" + toString( neededLength ) );
}
#ifdef E57_MAX_DEBUG
/// Verify padding at end is zero.
const char *p = reinterpret_cast<const char *>( this );
for ( unsigned i = neededLength; i < packetLength; i++ )
{
if ( p[i] != 0 )
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "i=" + toString( i ) );
}
/// Verify records and offsets are in sorted order
for ( unsigned i = 0; i < entryCount; i++ )
{
/// 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 ) +
" totalRecordCount=" + toString( totalRecordCount ) );
}
/// 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 ) );
}
/// 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 ) );
}
/// 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 ) );
}
}
#endif
}
#ifdef E57_DEBUG
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;
unsigned i;
for ( i = 0; i < 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;
}
if ( i < entryCount )
{
os << space( indent ) << entryCount - i << "more entries unprinted..." << std::endl;
}
}
#endif
//=============================================================================
// EmptyPacketHeader
void EmptyPacketHeader::verify( unsigned bufferLength ) const
{
/// Verify that packet is correct type
if ( packetType != EMPTY_PACKET )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( packetType ) );
}
/// 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 ) );
}
/// Check packet length is multiple of 4
if ( packetLength % 4 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString( packetLength ) );
}
/// 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 ) );
}
}
#ifdef E57_DEBUG
void EmptyPacketHeader::dump( int indent, std::ostream &os ) const
{
os << space( indent ) << "packetType: " << static_cast<unsigned>( packetType ) << std::endl;
os << space( indent ) << "packetLogicalLengthMinus1: " << packetLogicalLengthMinus1 << std::endl;
}
#endif

View File

@@ -1,141 +0,0 @@
/*
* 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 <cstdint>
#include <vector>
#include "Common.h"
namespace e57
{
class CheckedFile;
class PacketLock;
/// Packet types (in a compressed vector section)
enum
{
INDEX_PACKET = 0,
DATA_PACKET,
EMPTY_PACKET,
};
/// maximum size of CompressedVector binary data packet
constexpr int DATA_PACKET_MAX = ( 64 * 1024 );
class PacketReadCache
{
public:
PacketReadCache( CheckedFile *cFile, unsigned packetCount );
std::unique_ptr<PacketLock> lock( uint64_t packetLogicalOffset,
char *&pkt ); //??? pkt could be const
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout );
#endif
protected:
/// Only PacketLock can unlock the cache
friend class PacketLock;
void unlock( unsigned cacheIndex );
void readPacket( unsigned oldestEntry, uint64_t packetLogicalOffset );
struct CacheEntry
{
uint64_t logicalOffset_ = 0;
char buffer_[DATA_PACKET_MAX]; //! No need to init since it's a data buffer
unsigned lastUsed_ = 0;
};
unsigned lockCount_ = 0;
unsigned useCount_ = 0;
CheckedFile *cFile_ = nullptr;
std::vector<CacheEntry> entries_;
};
class PacketLock
{
public:
~PacketLock();
private:
/// Can't be copied or assigned
PacketLock( const PacketLock &plock );
PacketLock &operator=( const PacketLock &plock );
protected:
friend class PacketReadCache;
/// Only PacketReadCache can construct
PacketLock( PacketReadCache *cache, unsigned cacheIndex );
PacketReadCache *cache_ = nullptr;
unsigned int cacheIndex_ = 0;
};
class DataPacketHeader
{
public:
DataPacketHeader();
void reset();
void verify( unsigned bufferLength = 0 ) const; //???use
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const;
#endif
const uint8_t packetType = DATA_PACKET;
uint8_t packetFlags = 0;
uint16_t packetLogicalLengthMinus1 = 0;
uint16_t bytestreamCount = 0;
};
class DataPacket
{
public:
DataPacket();
void verify( unsigned bufferLength = 0 ) const;
char *getBytestream( unsigned bytestreamNumber, unsigned &byteCount );
unsigned getBytestreamBufferLength( unsigned bytestreamNumber );
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const;
#endif
static constexpr int PayloadSize = DATA_PACKET_MAX - sizeof( DataPacketHeader );
DataPacketHeader header;
uint8_t payload[PayloadSize]; //! No need to init since it's a data buffer
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,112 +0,0 @@
/*
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
* Copyright (c) 2020 PTC Inc.
*
* 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 "E57SimpleData.h"
namespace e57
{
//! most of the functions follows Reader
class ReaderImpl
{
public:
ReaderImpl( const ustring &filePath );
~ReaderImpl();
bool IsOpen() const;
bool Close();
bool GetE57Root( E57Root &fileHeader ) const;
int64_t GetImage2DCount() const;
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,
Image2DType &imageVisualType ) const;
int64_t ReadImage2DData( int64_t imageIndex, Image2DProjection imageProjection, Image2DType imageType,
void *pBuffer, int64_t start, int64_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 ReadData3DGroupsData( int64_t dataIndex, int64_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;
StructureNode GetRawE57Root() const;
VectorNode GetRawData3D() const;
VectorNode GetRawImages2D() const;
ImageFile GetRawIMF() const;
private:
ImageFile imf_;
StructureNode root_;
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

View File

@@ -1,240 +0,0 @@
/*
* 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.
*/
#include <cmath>
#include "CheckedFile.h"
#include "ScaledIntegerNodeImpl.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 )
{
// 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,
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 )
{
// don't checkImageFileOpen, NodeImpl() will do it
/// Enforce the given bounds on raw value
if ( scaledValue < scaledMinimum || scaledMaximum < scaledValue )
{
throw E57_EXCEPTION2( E57_ERROR_VALUE_OUT_OF_BOUNDS, "this->pathName=" + this->pathName() +
" scaledValue=" + toString( scaledValue ) +
" scaledMinimum=" + toString( scaledMinimum ) +
" scaledMaximum=" + toString( scaledMaximum ) );
}
}
bool ScaledIntegerNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
{
// don't checkImageFileOpen
/// Same node type?
if ( ni->type() != E57_SCALED_INTEGER )
{
return ( false );
}
/// Downcast to shared_ptr<ScaledIntegerNodeImpl>
std::shared_ptr<ScaledIntegerNodeImpl> ii( std::static_pointer_cast<ScaledIntegerNodeImpl>( ni ) );
/// minimum must match
if ( minimum_ != ii->minimum_ )
{
return ( false );
}
/// maximum must match
if ( maximum_ != ii->maximum_ )
{
return ( false );
}
/// scale must match
if ( scale_ != ii->scale_ )
{
return ( false );
}
/// offset must match
if ( offset_ != ii->offset_ )
{
return ( false );
}
/// ignore value_, doesn't have to match
/// Types match
return ( true );
}
bool ScaledIntegerNodeImpl::isDefined( const ustring &pathName )
{
// don't checkImageFileOpen
/// We have no sub-structure, so if path not empty return false
return pathName.empty();
}
int64_t ScaledIntegerNodeImpl::rawValue()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( value_ );
}
double ScaledIntegerNodeImpl::scaledValue()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( value_ * scale_ + offset_ );
}
int64_t ScaledIntegerNodeImpl::minimum()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( minimum_ );
}
double ScaledIntegerNodeImpl::scaledMinimum()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( minimum_ * scale_ + offset_ );
}
int64_t ScaledIntegerNodeImpl::maximum()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( maximum_ );
}
double ScaledIntegerNodeImpl::scaledMaximum()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( maximum_ * scale_ + offset_ );
}
double ScaledIntegerNodeImpl::scale()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( scale_ );
}
double ScaledIntegerNodeImpl::offset()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( offset_ );
}
void ScaledIntegerNodeImpl::checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin )
{
// don't checkImageFileOpen
/// 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() );
}
}
void ScaledIntegerNodeImpl::writeXml( ImageFileImplSharedPtr /*imf*/, CheckedFile &cf, int indent,
const char *forcedFieldName )
{
// don't checkImageFileOpen
ustring fieldName;
if ( forcedFieldName )
{
fieldName = forcedFieldName;
}
else
{
fieldName = elementName_;
}
cf << space( indent ) << "<" << fieldName << " type=\"ScaledInteger\"";
/// Don't need to write if are default values
if ( minimum_ != E57_INT64_MIN )
{
cf << " minimum=\"" << minimum_ << "\"";
}
if ( maximum_ != E57_INT64_MAX )
{
cf << " maximum=\"" << maximum_ << "\"";
}
if ( scale_ != 1.0 )
{
cf << " scale=\"" << scale_ << "\"";
}
if ( offset_ != 0.0 )
{
cf << " offset=\"" << offset_ << "\"";
}
/// Write value as child text, unless it is the default value
if ( value_ != 0 )
{
cf << ">" << value_ << "</" << fieldName << ">\n";
}
else
{
cf << "/>\n";
}
}
#ifdef E57_DEBUG
void ScaledIntegerNodeImpl::dump( int indent, std::ostream &os ) const
{
// don't checkImageFileOpen
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;
os << space( indent ) << "maximum: " << maximum_ << std::endl;
os << space( indent ) << "scale: " << scale_ << std::endl;
os << space( indent ) << "offset: " << offset_ << std::endl;
}
#endif
}

View File

@@ -1,76 +0,0 @@
#pragma once
/*
* 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.
*/
#include "NodeImpl.h"
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, double scaledValue = 0., double scaledMinimum = 0.,
double scaledMaximum = 0., double scale = 1.0, double offset = 0.0 );
~ScaledIntegerNodeImpl() override = default;
NodeType type() const override
{
return E57_SCALED_INTEGER;
}
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
bool isDefined( const ustring &pathName ) override;
int64_t rawValue();
double scaledValue();
int64_t minimum();
double scaledMinimum();
int64_t maximum();
double scaledMaximum();
double scale();
double offset();
void checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin ) override;
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
const char *forcedFieldName = nullptr ) override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
private:
int64_t value_;
int64_t minimum_;
int64_t maximum_;
double scale_;
double offset_;
};
}

View File

@@ -1,97 +0,0 @@
/*
* 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.
*/
#include "SectionHeaders.h"
namespace e57
{
#ifdef E57_DEBUG
void BlobSectionHeader::dump( int indent, std::ostream &os )
{
os << space( indent ) << "sectionId: " << sectionId << std::endl;
os << space( indent ) << "sectionLogicalLength: " << sectionLogicalLength << std::endl;
}
#endif
CompressedVectorSectionHeader::CompressedVectorSectionHeader()
{
/// 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 ???
for ( unsigned i = 0; i < sizeof( reserved1 ); i++ )
{
if ( reserved1[i] != 0 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_HEADER,
"i=" + toString( i ) + " reserved=" + toString( reserved1[i] ) );
}
}
/// Check section length is multiple of 4
if ( sectionLogicalLength % 4 )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_HEADER, "sectionLogicalLength=" + toString( sectionLogicalLength ) );
}
/// Check sectionLogicalLength is in bounds
if ( filePhysicalSize > 0 && sectionLogicalLength >= filePhysicalSize )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_HEADER, "sectionLogicalLength=" + toString( sectionLogicalLength ) +
" filePhysicalSize=" + toString( filePhysicalSize ) );
}
/// Check dataPhysicalOffset is in bounds
if ( filePhysicalSize > 0 && dataPhysicalOffset >= filePhysicalSize )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_HEADER, "dataPhysicalOffset=" + toString( dataPhysicalOffset ) +
" filePhysicalSize=" + toString( filePhysicalSize ) );
}
/// Check indexPhysicalOffset is in bounds
if ( filePhysicalSize > 0 && indexPhysicalOffset >= filePhysicalSize )
{
throw E57_EXCEPTION2( E57_ERROR_BAD_CV_HEADER, "indexPhysicalOffset=" + toString( indexPhysicalOffset ) +
" filePhysicalSize=" + toString( filePhysicalSize ) );
}
}
#ifdef E57_DEBUG
void CompressedVectorSectionHeader::dump( int indent, std::ostream &os ) const
{
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;
}
#endif
}

View File

@@ -1,67 +0,0 @@
#pragma once
/*
* 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.
*/
#include "Common.h"
namespace e57
{
enum
{
BLOB_SECTION = 0,
COMPRESSED_VECTOR_SECTION,
};
struct BlobSectionHeader
{
const uint8_t sectionId = BLOB_SECTION;
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 );
#endif
};
struct CompressedVectorSectionHeader
{
const uint8_t sectionId = COMPRESSED_VECTOR_SECTION;
uint8_t reserved1[7] = {}; // must be zero
uint64_t sectionLogicalLength = 0; // byte length of whole section
uint64_t dataPhysicalOffset = 0; // offset of first data packet
uint64_t indexPhysicalOffset = 0; // offset of first index packet
CompressedVectorSectionHeader();
void verify( uint64_t filePhysicalSize = 0 );
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const;
#endif
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,132 +0,0 @@
/*
* 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 "Common.h"
namespace e57
{
class ImageFileImpl;
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 );
template <typename T> void setTypeInfo( T *base, size_t stride = sizeof( T ) );
SourceDestBufferImpl( ImageFileImplWeakPtr destImageFile, const ustring &pathName, StringList *b );
ImageFileImplWeakPtr destImageFile() const
{
return destImageFile_;
}
ustring pathName() const
{
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;
}
int64_t getNextInt64();
int64_t getNextInt64( double scale, double offset );
float getNextFloat();
double getNextDouble();
ustring getNextString();
void setNextInt64( int64_t value );
void setNextInt64( int64_t value, double scale, double offset );
void setNextFloat( float value );
void setNextDouble( double value );
void setNextString( const ustring &value );
void checkCompatible( const std::shared_ptr<SourceDestBufferImpl> &newBuf ) const;
#ifdef E57_DEBUG
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
//??? 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
};
}

View File

@@ -1,145 +0,0 @@
/*
* 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.
*/
#include "StringNodeImpl.h"
#include "CheckedFile.h"
namespace e57
{
StringNodeImpl::StringNodeImpl( ImageFileImplWeakPtr destImageFile, const ustring &value ) :
NodeImpl( destImageFile ), value_( value )
{
// don't checkImageFileOpen, NodeImpl() will do it
}
bool StringNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
{
// don't checkImageFileOpen
/// Same node type?
if ( ni->type() != E57_STRING )
{
return ( false );
}
/// ignore value_, doesn't have to match
/// Types match
return ( true );
}
bool StringNodeImpl::isDefined( const ustring &pathName )
{
// don't checkImageFileOpen
/// We have no sub-structure, so if path not empty return false
return pathName.empty();
}
ustring StringNodeImpl::value()
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return ( value_ );
}
void StringNodeImpl::checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin )
{
// don't checkImageFileOpen
/// 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() );
}
}
void StringNodeImpl::writeXml( ImageFileImplSharedPtr /*imf*/, CheckedFile &cf, int indent,
const char *forcedFieldName )
{
// don't checkImageFileOpen
ustring fieldName;
if ( forcedFieldName )
{
fieldName = forcedFieldName;
}
else
{
fieldName = elementName_;
}
cf << space( indent ) << "<" << fieldName << " type=\"String\"";
/// Write value as child text, unless it is the default value
if ( value_.empty() )
{
cf << "/>\n";
}
else
{
cf << "><![CDATA[";
size_t currentPosition = 0;
size_t len = value_.length();
/// 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.
cf << value_.substr( currentPosition );
break;
}
/// 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
cf << "]]><![CDATA[";
/// Keep looping to send the ">" plus the remaining part of the string
currentPosition = found + 2;
}
cf << "]]></" << fieldName << ">\n";
}
}
#ifdef E57_DEBUG
void StringNodeImpl::dump( int indent, std::ostream &os ) const
{
os << space( indent ) << "type: String"
<< " (" << type() << ")" << std::endl;
NodeImpl::dump( indent, os );
os << space( indent ) << "value: '" << value_ << "'" << std::endl;
}
#endif
}

View File

@@ -1,61 +0,0 @@
#pragma once
/*
* 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.
*/
#include "NodeImpl.h"
namespace e57
{
class StringNodeImpl : public NodeImpl
{
public:
explicit StringNodeImpl( ImageFileImplWeakPtr destImageFile, const ustring &value = "" );
~StringNodeImpl() override = default;
NodeType type() const override
{
return E57_STRING;
}
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
bool isDefined( const ustring &pathName ) override;
ustring value();
void checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin ) override;
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
const char *forcedFieldName = nullptr ) override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
private:
ustring value_;
};
}

View File

@@ -1,470 +0,0 @@
/*
* 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.
*/
#include <climits>
#include "CheckedFile.h"
#include "ImageFileImpl.h"
#include "StructureNodeImpl.h"
using namespace e57;
StructureNodeImpl::StructureNodeImpl( ImageFileImplWeakPtr destImageFile ) : NodeImpl( destImageFile )
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
}
NodeType StructureNodeImpl::type() const
{
/// don't checkImageFileOpen
return E57_STRUCTURE;
}
//??? use visitor?
bool StructureNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
{
/// don't checkImageFileOpen
/// Same node type?
if ( ni->type() != E57_STRUCTURE )
{
return ( false );
}
/// Downcast to shared_ptr<StructureNodeImpl>
std::shared_ptr<StructureNodeImpl> si( std::static_pointer_cast<StructureNodeImpl>( ni ) );
/// Same number of children?
if ( childCount() != si->childCount() )
{
return ( false );
}
/// 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)
if ( myChildsFieldName == si->children_.at( i )->elementName() )
{
if ( !children_.at( i )->isTypeEquivalent( si->children_.at( i ) ) )
{
return ( false );
}
}
else
{
/// Children in different order, so lookup by name and check if equal
/// to our child
if ( !si->isDefined( myChildsFieldName ) )
{
return ( false );
}
if ( !children_.at( i )->isTypeEquivalent( si->lookup( myChildsFieldName ) ) )
{
return ( false );
}
}
}
/// Types match
return ( true );
}
bool StructureNodeImpl::isDefined( const ustring &pathName )
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
NodeImplSharedPtr ni( lookup( pathName ) );
return ( ni != nullptr );
}
void StructureNodeImpl::setAttachedRecursive()
{
/// Mark this node as attached to an ImageFile
isAttached_ = true;
/// Not a leaf node, so mark all our children
for ( auto &child : children_ )
{
child->setAttachedRecursive();
}
}
int64_t StructureNodeImpl::childCount() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
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() ) );
}
return ( children_.at( static_cast<unsigned>( index ) ) );
}
NodeImplSharedPtr StructureNodeImpl::get( const ustring &pathName )
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
NodeImplSharedPtr ni( lookup( pathName ) );
if ( !ni )
{
throw E57_EXCEPTION2( E57_ERROR_PATH_UNDEFINED, "this->pathName=" + this->pathName() + " pathName=" + pathName );
}
return ( ni );
}
NodeImplSharedPtr StructureNodeImpl::lookup( const ustring &pathName )
{
/// don't checkImageFileOpen
//??? use lookup(fields, level) instead, for speed.
bool isRelative;
std::vector<ustring> fields;
ImageFileImplSharedPtr imf( destImageFile_ );
imf->pathNameParse( pathName, isRelative, fields ); // throws if bad pathName
if ( isRelative || isRoot() )
{
if ( fields.empty() )
{
if ( isRelative )
{
return NodeImplSharedPtr(); /// empty pointer
}
else
{
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++ )
{
if ( fields.at( 0 ) == children_.at( i )->elementName() )
{
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() );
/// Call lookup on root
return ( root->lookup( pathName ) );
}
}
void StructureNodeImpl::set( int64_t index64, NodeImplSharedPtr ni )
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
auto index = static_cast<unsigned>( index64 );
/// 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() ) );
}
/// 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 ) );
}
/// 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() );
}
/// 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 ( isTypeConstrained() )
{
throw E57_EXCEPTION2( E57_ERROR_HOMOGENEOUS_VIOLATION, "this->pathName=" + this->pathName() );
}
ni->setParent( shared_from_this(), elementName.str() );
children_.push_back( ni );
}
void StructureNodeImpl::set( const ustring &pathName, NodeImplSharedPtr ni, bool autoPathCreate )
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
//??? parse pathName! throw if impossible, absolute and multi-level paths...
//??? enforce type constraints on path (non-zero index types match zero index
// types for VECTOR,
// COMPRESSED_VECTOR
#ifdef E57_MAX_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.
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"
set( fields, 0, ni, autoPathCreate );
}
else
{
/// 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 )
{
#ifdef E57_MAX_VERBOSE
std::cout << "StructureNodeImpl::set: level=" << level << std::endl;
for ( unsigned i = 0; i < fields.size(); i++ )
{
std::cout << " field[" << i << "]: " << fields.at( i ) << std::endl;
}
#endif
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
//??? check if field is numeric string (e.g. "17"), verify number is same as
// index, else throw
// bad_path
/// 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=/" );
}
/// 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] );
}
/// Recurse on child
child->set( fields, level + 1, ni );
return;
}
}
/// Didn't find matching field name, so have a 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() );
}
/// Check if we are at bottom level
if ( level == fields.size() - 1 )
{
/// 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
if ( !autoPathCreate )
{
throw E57_EXCEPTION2( E57_ERROR_PATH_UNDEFINED,
"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
NodeImplSharedPtr parent( shared_from_this() );
for ( ; level != fields.size() - 1; level++ )
{
std::shared_ptr<StructureNodeImpl> child( new StructureNodeImpl( destImageFile_ ) );
parent->set( fields.at( level ), child );
parent = child;
}
parent->set( fields.at( level ), ni );
}
}
void StructureNodeImpl::append( NodeImplSharedPtr ni )
{
/// don't checkImageFileOpen, set() will do it
/// 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
/// Not a leaf node, so check all our children
for ( auto &child : children_ )
{
child->checkLeavesInSet( pathNames, origin );
}
}
//??? use visitor?
void StructureNodeImpl::writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent, const char *forcedFieldName )
{
/// don't checkImageFileOpen
ustring fieldName;
if ( forcedFieldName )
{
fieldName = forcedFieldName;
}
else
{
fieldName = elementName_;
}
cf << space( indent ) << "<" << fieldName << " type=\"Structure\"";
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 ( isRoot() && shared_from_this() == imf->root() )
{
bool gotDefaultNamespace = false;
for ( size_t i = 0; i < imf->extensionsCount(); i++ )
{
const char *xmlnsExtension;
if ( imf->extensionsPrefix( i ).empty() )
{
gotDefaultNamespace = true;
xmlnsExtension = "xmlns";
}
else
{
xmlnsExtension = "xmlns:";
}
const int index = static_cast<int>( i );
cf << "\n"
<< space( numSpaces ) << xmlnsExtension << imf->extensionsPrefix( index ) << "=\""
<< imf->extensionsUri( index ) << "\"";
}
/// 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 << "\"";
}
}
if ( !children_.empty() )
{
cf << ">\n";
/// Write all children nested inside Structure element
for ( auto &child : children_ )
{
child->writeXml( imf, cf, indent + 2 );
}
/// Write closing tag
cf << space( indent ) << "</" << fieldName << ">\n";
}
else
{
/// XML element has no child elements
cf << "/>\n";
}
}
//??? use visitor?
#ifdef E57_DEBUG
void StructureNodeImpl::dump( int indent, std::ostream &os ) const
{
/// don't checkImageFileOpen
os << space( indent ) << "type: Structure"
<< " (" << type() << ")" << std::endl;
NodeImpl::dump( indent, os );
for ( unsigned i = 0; i < children_.size(); i++ )
{
os << space( indent ) << "child[" << i << "]:" << std::endl;
children_.at( i )->dump( indent + 2, os );
}
}
#endif

View File

@@ -1,71 +0,0 @@
/*
* 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 "NodeImpl.h"
namespace e57
{
class StructureNodeImpl : public NodeImpl
{
public:
StructureNodeImpl( ImageFileImplWeakPtr destImageFile );
~StructureNodeImpl() override = default;
NodeType type() const override;
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
bool isDefined( const ustring &pathName ) override;
void setAttachedRecursive() override;
virtual int64_t childCount() const;
virtual NodeImplSharedPtr get( int64_t index );
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;
virtual void append( NodeImplSharedPtr ni );
void checkLeavesInSet( const StringSet &pathNames, NodeImplSharedPtr origin ) override;
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
const char *forcedFieldName = nullptr ) override;
#ifdef E57_DEBUG
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_;
};
}

View File

@@ -1,139 +0,0 @@
/*
* 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.
*/
#include "VectorNodeImpl.h"
#include "CheckedFile.h"
namespace e57
{
VectorNodeImpl::VectorNodeImpl( ImageFileImplWeakPtr destImageFile, bool allowHeteroChildren ) :
StructureNodeImpl( destImageFile ), allowHeteroChildren_( allowHeteroChildren )
{
/// don't checkImageFileOpen, StructNodeImpl() will do it
}
bool VectorNodeImpl::isTypeEquivalent( NodeImplSharedPtr ni )
{
/// don't checkImageFileOpen
/// Same node type?
if ( ni->type() != E57_VECTOR )
{
return ( false );
}
std::shared_ptr<VectorNodeImpl> ai( std::static_pointer_cast<VectorNodeImpl>( ni ) );
/// allowHeteroChildren must match
if ( allowHeteroChildren_ != ai->allowHeteroChildren_ )
{
return ( false );
}
/// Same number of children?
if ( childCount() != ai->childCount() )
{
return ( false );
}
/// Check each child, must be in same order
for ( unsigned i = 0; i < childCount(); i++ )
{
if ( !children_.at( i )->isTypeEquivalent( ai->children_.at( i ) ) )
{
return ( false );
}
}
/// Types match
return ( true );
}
bool VectorNodeImpl::allowHeteroChildren() const
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
return allowHeteroChildren_;
}
void VectorNodeImpl::set( int64_t index64, NodeImplSharedPtr ni )
{
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
if ( !allowHeteroChildren_ )
{
/// 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() );
}
}
}
///??? for now, use base implementation
StructureNodeImpl::set( index64, ni );
}
void VectorNodeImpl::writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent, const char *forcedFieldName )
{
/// don't checkImageFileOpen
ustring fieldName;
if ( forcedFieldName )
{
fieldName = forcedFieldName;
}
else
{
fieldName = elementName_;
}
cf << space( indent ) << "<" << fieldName << " type=\"Vector\" allowHeterogeneousChildren=\""
<< static_cast<int64_t>( allowHeteroChildren_ ) << "\">\n";
for ( auto &child : children_ )
{
child->writeXml( imf, cf, indent + 2, "vectorChild" );
}
cf << space( indent ) << "</" << fieldName << ">\n";
}
#ifdef E57_DEBUG
void VectorNodeImpl::dump( int indent, std::ostream &os ) const
{
/// don't checkImageFileOpen
os << space( indent ) << "type: Vector"
<< " (" << type() << ")" << std::endl;
NodeImpl::dump( indent, os );
os << space( indent ) << "allowHeteroChildren: " << allowHeteroChildren() << std::endl;
for ( unsigned i = 0; i < children_.size(); i++ )
{
os << space( indent ) << "child[" << i << "]:" << std::endl;
children_.at( i )->dump( indent + 2, os );
}
}
#endif
}

View File

@@ -1,59 +0,0 @@
#pragma once
/*
* 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.
*/
#include "StructureNodeImpl.h"
namespace e57
{
class VectorNodeImpl : public StructureNodeImpl
{
public:
explicit VectorNodeImpl( ImageFileImplWeakPtr destImageFile, bool allowHeteroChildren );
~VectorNodeImpl() override = default;
NodeType type() const override
{
return E57_VECTOR;
}
bool isTypeEquivalent( NodeImplSharedPtr ni ) override;
bool allowHeteroChildren() const;
void set( int64_t index, NodeImplSharedPtr ni ) override;
void writeXml( ImageFileImplSharedPtr imf, CheckedFile &cf, int indent,
const char *forcedFieldName = nullptr ) override;
#ifdef E57_DEBUG
void dump( int indent = 0, std::ostream &os = std::cout ) const override;
#endif
private:
bool allowHeteroChildren_;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,87 +0,0 @@
/*
* Copyright (c) 2010 Stan Coleby (scoleby@intelisum.com)
* Copyright (c) 2020 PTC Inc.
*
* 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 "E57SimpleData.h"
namespace e57
{
//! most of the functions follows Writer
class WriterImpl
{
public:
WriterImpl( const ustring &filePath, const ustring &coordinateMetaData );
~WriterImpl();
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 );
int64_t NewData3D( Data3D &data3DHeader );
template <typename COORDTYPE>
CompressedVectorWriter SetUpData3DPointsData( int64_t dataIndex, size_t pointCount,
const Data3DPointsData_t<COORDTYPE> &buffers );
bool WriteData3DGroupsData( int64_t dataIndex, int64_t groupCount, int64_t *idElementValue,
int64_t *startPointIndex, int64_t *pointCount );
StructureNode GetRawE57Root();
VectorNode GetRawData3D();
VectorNode GetRawImages2D();
ImageFile GetRawIMF();
private:
ImageFile imf_;
StructureNode root_;
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