segyio-1.8.3/0000775000372000037200000000000013407674361012437 5ustar travistravissegyio-1.8.3/config.sh0000664000372000037200000000114713407674361014243 0ustar travistravis#!/bin/sh function run_tests { set -x python -c "import segyio; print(segyio.__version__)" python ../python/examples/scan_min_max.py ../test-data/small.sgy } function pre_build { set -e if [ -n "$IS_OSX" ]; then return; fi if [ -d build-centos5 ]; then return; fi # the cmakes available in yum for centos5 are too old (latest 2.11.x), so # fetch a newer version pypi python -m pip install cmake mkdir build-centos5 pushd build-centos5 cmake --version cmake .. -DBUILD_PYTHON=OFF -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON make install popd } segyio-1.8.3/breaking-changes.md0000664000372000037200000000330613407674361016153 0ustar travistravis# Planned breaking changes for segyio 2 This documents describe the planned breaking changes for segyio >= 2. ## libsegyio ### removal of linkage of ebcdic2ascii and friends, and ibm2ieee The conversion functions are linkable today, but the symbols are not exposed in any headers. Giving these functions public linkage (for testing purposes) was a mistake, but hopefully no users will be affected as the symbols never appears in the header file. Affected functions: - `ebcdic2ascii` - `ascii2ebcdic` - `ibm2ieee` - `ieee2ibm` - `segy_seek` - `segy_ftell` ## python ### accessing closed files raises ValueError Calling methods on closed files should not raise `IOError`, but `ValueError`, in order to be uniform with python's own file object. Most users shouldn't (or wouldn't) use this error for control flow or recovery, but in order to account for it, the change is postponed. ### f.text no longer implicitly resolves to f.text[0] The implicit accessing of the mandatory text header is inconsistent and error prone, and won't work in segyio2. In segyio2, the only way to grab the mandatory text header is `f.text[0]` ### str(f.text[n]) removed The implicit string conversion should be either tied to fmt or other explicit methods, instead of implicitly resolving into a newline-interleaved 80-linewidth string ### f.text[n] always returns 3200 bytes buffer object Currently, the returned buffer assumes the contents are somewhat string-like, and has some wonky behaviour when there are 0-bytes in the text headers, and not proper whitespace paddings. In segyio2, this behaviour will be reviewed for consistency, so that 0-bytes-in-buffers are handled gracefully, and textheaders can be indexed into reliably and safely. segyio-1.8.3/MANIFEST.in0000664000372000037200000000007713407674361014201 0ustar travistravisinclude License.md include README.md recursive-include src *.h segyio-1.8.3/requirements.txt0000664000372000037200000000001613407674361015720 0ustar travistravisnumpy >= 1.10 segyio-1.8.3/multibuild/0000775000372000037200000000000013407674361014611 5ustar travistravissegyio-1.8.3/changelog.md0000664000372000037200000003272213407674361014716 0ustar travistravis# 1.8.3 * Check endianness variable properly # 1.8.2 * Pass HOST_BIG_ENDIAN as preprocessor directive, not compiler option # 1.8.1 * Fixed a docstring formatting issue * Fixed a race condition in test suite # 1.8.0 * segyio has learned the seismic unix file format, and can read and write SU files. This feature is found in the segyio.su module * segyio supports least-significant-byte (LSB/little-endian) first formatted files * Fixed a bug that caused writing headers in non-linear mode very slow, and wrong under some conditions * segyio also considers files with descending line/offset numbers sorted, not just ascending * The python file handle has learned the interpret method, which allows specifying structure directly, rather than inferring it from file metadata. This is particularly useful for files with structure, but broken headers * A new family of from_array functions are added to the tools module, intended for quick-and-easy storing a 2/3/4D volume on disk * Sorting defaults to inline in segyio.create if nothing is specified * Text.__setitem__ used a wrong variable and didn't really work, but is now fixed * Internal imports are tidied up * The test suite in both Python and C++ have seen some minor improvements * An experimental C++ interface is available for source builds, but is not considered stable - internals and interface can change with no prior notice. The experimental interface is enabled when segyio is built with -DEXPERIMENTAL=ON # 1.7.1 * Fixed an issue where writing traces on memory-mapped files was a no-op * Depth slices dimensions are always in fast-by-slow * catb/catr has some new output formats * Some docs entries updated and fixed # 1.7.0 * segyio has learned to open non-ascii file paths on Windows * Fixed an issue where segyio-catr would sometimes print the same trace twice * segyio no longer incorrectly considers files where the inline/crossline/offset triple doesn't change sorted * The test suite has seen some overhaul, making test cases more focused on the actual thing to test * Checking sorting won't silently fail when the offset-word is broken * `f.text` is now a Sequence, meaning it has slicing and other common array operations * The makefiles no longer build both static and shared libraries, but rather respect the BUILD_SHARED_LIBS variable * Python 3.7 support * Various refactoring and internal improvements # 1.6.0 * segyio has learned to handle int16 and int32 sample formats * segyio has learned to write any array_likes with any float-convertible contents. `f.trace = np.linspace(0, 1, 0.01)` works as expected. * segyio types have been extended to be more container-like, and conform to more protocols. Notably, headers and lines are properly dict_like, and traces are properly array_like * `trace.ref` added, a write-back mode where changes to yielded trace data are written back to disk * `trace.raw` has been improved, is faster and supports setitem and the container protocol * Headers have learned to accept (seismic unix) keywords in `update`, so `header.update(cdpx=10)` works as expected * `f.dtype` added, this is the dtype used in all segyio-provided numpy arrays, and reflects the underlying data format * `f.readonly` added, to query if file handles are writable * segyio gracefully handle non-contiguous and more array_likes in setitem * The type requirements of `f.samples` has been relaxed, and it now is whatever numpy uses as default * segyio now assumes IBM float if the format identifier is meaningless * Some exception types are cleaned up, notably header key misses raise KeyError, not IndexError * General speed and clarity improvements, some more exception guarantees * segyio has learned to raise an error when provided with too short data traces * segyio has started raising deprecation warnings when using to-be-removed features * The python library has overall been simplified * Lots of new documentation has been written, the sphinx docs structure has been overhauled # 1.5.3 * segyio-catr has learned to handle no arguments, and as a results read the first trace header as intended * segyio-catr has its help text and man page corrected * segyio-crop has learned to say how many traces it copies * segyio-crop has learned to warn when no traces are copied * segyio-crop has learned not to overwrite its input file when source and dest is the same * The makefiles understand the BUILD_DOC option, to build the python docs with sphinx * Test suite has some speed and robustness improvements # 1.5.2 * `open` and `create` handle anything string-convertible as filename argument * pytest replaces unittest, both as library and test driver * segyio-crop now respects the byte-offset arguments, instead of just ignoring them and using 189 & 193 from SEG-Y revision 1 * Some errors in readme and documentation is cleared up * Fixed a bug in create that would trigger 16-bit integer overflow, effectively breaking any file with more than 65k traces. # 1.5.0 * A bug making an external text header disappear has been fixed * The python extension has been changed to use C++ features, simplifying code and dropping the use of capsules * segyio-cath sets non-zero status code on failures * Application testing is moved from python to cmake, giving a large speedup * The IndexError message when accessing headers out-of-range has been improved * Some work has been moved from python into the extension * Error messages in python have received an overhaul * Errors produced when memory-mapping files are made consistent with fstream sourced errors # 1.4.0 * segyio has learned how to resample a file (`segyio.tools.resample`). This function does not actually touch the data traces, but rewrites the header fields and attributes required to persistently change sample rate. Interpolation of data traces must be done manually, but for a strict reinterpretation this function is sufficient * segyio has learned to read enough structure from a file to create a new file with the same dimensions and lines (`segyio.tools.metadata`) * segyio has learned to create unstructured files (only traces, no inlines or crosslines) * `f.text[0] =` requires `bytes` convertability. This catches some errors that were previously fatal or silent * `f.text` broken internal buffer allocations fixed * `f.text[n] =` supports strings longer or shorter than 3200 bytes by truncating or padding, respectively * Fixed a bug where a particular length of mode strings caused errors * `segyio.open('w')` raises an exception, instead of silently truncating the file and failing later when the file size does not match the expected. * `segy_traces` now fails if `trace0` is outside domain, instead of silently returning garbage * Return correct size for dirty, newly-created files. This means carefully created new files can be `mmap`d earlier * Methods on closed files always raise exceptions * `mmap` support improved - all C functions are `mmap` aware. * The file is now closed after a successful `mmap` call * `str.format` used for string interpolation over the `%` operator * Several potential issues found by static analysis, such as non-initialised temporaries, divide-by-zero code paths, and leak-errors (in process teardown) addressed, to reduce noise and improve safety * Error message on failure in `segyio.tools.dt` improved * Error message on unparsable global binary header improved changes for the next major release * Catch2 is introduced to test the core C library, replacing the old `test/segy.c` family of tests * Contract for `segy_traces` clarified in documentation * Docstrings improved for `depth_slice` and `segyio.create` * A new document, `breaking-changes.md`, lists planned deprecations and API * The readme has gotten a makeover, with better structure, an index, and more examples * `setup.py` requires setuptools >= 28. A rather recent setuptools was always a requirement, but not codified * scan-build (clang analysis) enabled on Travis # 1.3.9 * Fix OS X wheel packaging. # 1.3.8 * Automate python ast analysis with bandit on travis * The installed python extension is built without rpath * The numpy minimum requirement is handled in setup.py * The python installation layout can be configured via cmake e.g. -DPYTHON_INSTALL_LAYOUT=deb # 1.3.7 * Makefiles can turn off version detection from git from env or via args # 1.3.6 * Applications no longer spuriously ignore arguments * All assertClose calls in tests have non-zero epsilon # 1.3.5 * make install respects DESTDIR, also for python files # 1.3.4 * Reading a slice in gather mode is significantly faster * Use ftello when available to support large files on systems where long is 32-bit * The python extension is changed to use C++; a C++ compiler is now required, not just optional, when building the python extension * Many internal and infrastructure improvements * The python library is built with setuptools - still integrated with cmake. Users building from source can still do cmake && make * Git tag is now authority on version numbers, as opposed to the version string recorded in the cmake file. * General building and infrastructure improvements # 1.3.3 * Infrastructure fixes # 1.3.2 * Add test for segy-cath * Fix memory double-free error in subtr functions # 1.3.1 * Fix a typo in segyio-crop --version * Some building improvements # 1.3.0 * segyio is now meant to be used as proper versions, not trunk checkouts. changelogs from now on will be written when new versions are released, not on a monthly basis. * Minor typo fixes in segyio-cath help * Applications now come with man pages * `header` modes handle negative indexing * `header.update` handle any key-value iterable * New application: segyio-catr for printing trace headers * New application: segyio-catb for printing the binary header * New application: segyio-crop for copying sub cubes # 2017.06 * seismic unix-style aliases are available for python in the segyio.su namespace * segyio has learned how to calculate the rotation of the cube (segy_rotation_cw and segyio.tools.rotation) * The python header objects behave more as dicts as expected * The new program segyio-cath is added, a cat-like program that concatenate text headers. * Infrastructure improvements * segyio for python is available via pypi (pip) * segyio is now meant to be consumed with binary downloads of versions, but with a rapid release cycle. Releases within a major release will be backwards compatible * Shared linking of the python extension is considered deprecated on Windows. # 2017.05 * Requirements for the shape of the right hand side of `f.trace[:] =` expressions are relaxed and accepts more inputs * C interface slightly cleaned up for C99 compliance * C library can reason on arbitrary header words for offsets, not just 37 # 2017.04 * Examples in the readme * Delay recording time (t0) is interpreted as milliseconds, not microseconds * Some minor optimisations * segy_mmap is more exception safe * The applications warn if mmap fails * Support for static analysis with cppcheck * The statoil/pycmake repo is used for python integration in cmake * Minor milli/microsecond bugfixes in mex bindings * tools.wrap added for printing textual headers to screen or file # 2017.03 * Float conversions (ibm <-> native) has been optimised and is much faster * `segy_binheader_size` returns signed int like its friends * `sample_interval` steps are now floats * Multiple internal bug fixes * Some buffer leaks are plugged * segyio has learned to deal with files without good geometry. If `strict = False` is passed to segyio.open, and a file is without well-sorted inlines/crosslines, open will return a file handle, but with geometry-dependent modes disabled * `file.samples` returns a list of samples, not number of samples * Readme has been improved. * `trace[int]` is more robust w.r.t. inputs * A new mode has been added; gather. gather depends on a good geometry, and its getitem `[il, xl, slice(offsets)]` returns all offsets for an inline/crossline intersection # 2017.02 * segyio has learned to deal with large files (>4G) on more platforms * segyio can read quickly attributes (trace header words) over the full file * python can tell the fast and slow directions apart * Reading depth slices is much faster * tools.collect for gathering read samples into a single numpy ndarray * tools.cube for easily reading a full cube * tools.native for fast third-party segy-to-native float conversion * File opening in binary mode is now enforced * Data types have been overhauled (prefer signed integers) * Enumerations have been SEGY prefixed to reduce collisions * Building shared libs can be switched on/off on cmake invocation * Makefiles and CI overhauls # 2017.01 * Matlab has learned about prestack files * Reading traces in matlab no longer fails when not reading the whole file * Matlab argument keys have been renamed # 2016.11 * Fixed some condtions where a failed write would corrupt trace data * Fixed a memory leak bug * VERSION string added to python * Experimental memory-mapped file support * Line-oriented C functions are offset aware * Python offset property exposes offset numbers, not just count * Support for pre-stack files, with new subindexing syntax, line[n, offset] * Improved python repl (shell, read-eval-print-loop) support * The widgets have color- and layout selectors # 2016.10 * Matlab tests can optionally be turned off * The application Segyviewer is embeddable and provided by the segyview sub library * libcwrap has been replaced fully by the python C api * OS X and experimental Windows support * A new sub mode for traces, raw, for eager reading of trace data segyio-1.8.3/README.md0000664000372000037200000004740013407674361013723 0ustar travistravis# segyio # [![Travis](https://img.shields.io/travis/Statoil/segyio/master.svg?label=travis)](https://travis-ci.org/Statoil/segyio) [![Appveyor](https://ci.appveyor.com/api/projects/status/2i5cr8ui2t9qbxk9?svg=true)](https://ci.appveyor.com/project/statoil-travis/segyio) [![PyPI Updates](https://pyup.io/repos/github/Statoil/segyio/shield.svg)](https://pyup.io/repos/github/Statoil/segyio/) [![Python 3](https://pyup.io/repos/github/Statoil/segyio/python-3-shield.svg)](https://pyup.io/repos/github/Statoil/segyio/) [readthedocs](https://segyio.readthedocs.io/) ## Index ## * [Introduction](#introduction) * [Feature summary](#feature-summary) * [Getting started](#getting-started) * [Quick start](#quick-start) * [Get segyio](#get-segyio) * [Build segyio](#build-segyio) * [Tutorial](#tutorial) * [Basics](#basics) * [Modes](#modes) * [Mode examples](#mode-examples) * [Goals](#project-goals) * [Contributing](#contributing) * [Examples](#examples) * [Common issues](#common-issues) * [History](#history) ## Introduction ## Segyio is a small LGPL licensed C library for easy interaction with SEG-Y formatted seismic data, with language bindings for Python and Matlab. Segyio is an attempt to create an easy-to-use, embeddable, community-oriented library for seismic applications. Features are added as they are needed; suggestions and contributions of all kinds are very welcome. To catch up on the latest development and features, see the [changelog](changelog.md). To write future proof code, consult the planned [breaking changes](breaking-changes.md). ## Feature summary ## * A low-level C interface with few assumptions; easy to bind to other languages * Read and write binary and textual headers * Read and write traces and trace headers * Simple, powerful, and native-feeling Python interface with numpy integration * xarray integration with netcdf_segy * Some simple applications with unix philosophy ## Getting started ## When segyio is built and installed, you're ready to start programming! Check out the [tutorial](#tutorial), [examples](#examples), and the [example programs](python/examples). For a technical reference with examples and small recipes, [read the docs](https://segyio.readthedocs.io/) or start your favourite Python interpreter and type `help(segyio)` to get started - it is written with pydoc and should integrate well with IDLE, pycharm and other Python tools. ### Quick start ### ```python import segyio import numpy as np with segyio.open('file.sgy') as f: for trace in f.trace: filtered = trace[np.where(trace < 1e-2)] ``` See the [examples](#examples) for more. ### Get segyio ### A copy of segyio is available both as pre-built binaries and source code: * In Debian [unstable](https://packages.debian.org/source/sid/segyio) * `apt install python3-segyio` * Wheels for Python from [PyPI](https://pypi.python.org/pypi/segyio/) * `pip install segyio` * Source code from [github](https://github.com/statoil/segyio) * `git clone https://github.com/statoil/segyio` * Source code in [tarballs](https://github.com/Statoil/segyio/releases) ### Build segyio ### To build segyio you need: * A C99 compatible C compiler (tested mostly on gcc and clang) * A C++ compiler for the Python extension, and C++11 for the tests * [CMake](https://cmake.org/) version 2.8.12 or greater * [Python](https://www.python.org/) 2.7 or 3.x. * [numpy](http://www.numpy.org/) version 1.10 or greater * [setuptools](https://pypi.python.org/pypi/setuptools) version 28 or greater * [setuptools-scm](https://pypi.python.org/pypi/setuptools_scm) * [pytest](https://pypi.org/project/pytest) To build the documentation, you also need [sphinx](https://pypi.org/project/Sphinx) To build and install segyio, perform the following actions in your console: ```bash git clone https://github.com/Statoil/segyio mkdir segyio/build cd segyio/build cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local make make install ``` `make install` must be done as root for a system install; if you want to install in your home directory, add `-DCMAKE_INSTALL_PREFIX=~/` or some other appropriate directory, or `make DESTDIR=~/ install`. Please ensure your environment picks up on non-standard install locations (PYTHONPATH, LD_LIBRARY_PATH and PATH). If you have multiple Python installations, or want to use some alternative interpreter, you can help cmake find the right one by passing `-DPYTHON_EXECUTABLE=/opt/python/binary` along with install prefix and build type. To build the matlab bindings, invoke CMake with the option `-DBUILD_MEX=ON`. In some environments the Matlab binaries are in a non-standard location, in which case you need to help CMake find the matlab binaries by passing `-DMATLAB_ROOT=/path/to/matlab`. #### Developers #### It's recommended to build in debug mode to get more warnings and to embed debug symbols in the objects. Substituting `Debug` for `Release` in the `CMAKE_BUILD_TYPE` is plenty. Tests are located in the language/tests directories, and it's highly recommended that new features added are demonstrated for correctness and contract by adding a test. All tests can be run by invoking `ctest`. Feel free to use the tests already written as a guide. After building segyio you can run the tests with `ctest`, executed from the build directory. Please note that to run the Python examples you need to let your environment know where to find the Python library. It can be installed as a user, or on adding the segyio/build/python library to your pythonpath. ## Tutorial ## All code in this tutorial assumes segyio is imported, and that numpy is available as np. ```python import segyio import numpy as np ``` This tutorial assumes you're familiar with Python and numpy. For a refresh, check out the [python tutorial](https://docs.python.org/3/tutorial/) and [numpy quickstart](https://docs.scipy.org/doc/numpy-dev/user/quickstart.html) ### Basics ### Opening a file for reading is done with the `segyio.open` function, and idiomatically used with context managers. Using the `with` statement, files are properly closed even in the case of exceptions. By default, files are opened read-only. ```python with segyio.open(filename) as f: ... ``` Open accepts several options (for more a more comprehensive reference, check the open function's docstring with `help(segyio.open)`. The most important option is the second (optional) positional argument. To open a file for writing, do `segyio.open(filename, 'r+')`, from the C `fopen` function. Files can be opened in *unstructured* mode, either by passing `segyio.open` the optional arguments `strict=False`, in which case not establishing structure (inline numbers, crossline numbers etc.) is not an error, and `ignore_geometry=True`, in which case segyio won't even try to set these internal attributes. The segy file object has several public attributes describing this structure: * `f.ilines` Inferred inline numbers * `f.xlines` Inferred crossline numbers * `f.offsets` Inferred offsets numbers * `f.samples` Inferred sample offsets (frequency and recording time delay) * `f.unstructured` True if unstructured, False if structured * `f.ext_headers` The number of extended textual headers If the file is opened *unstructured*, all the line properties will will be `None`. ### Modes ### In segyio, data is retrived and written through so-called *modes*. Modes are abstract arrays, or addressing schemes, and change what names and indices mean. All modes are properties on the file handle object, support the `len` function, and reads and writes are done through `f.mode[]`. Writes are done with assignment. Modes support array slicing inspired by numpy. The following modes are available: * `trace` The trace mode offers raw addressing of traces as they are laid out in the file. This, along with `header`, is the only mode available for unstructured files. Traces are enumerated `0..len(f.trace)`. Reading a trace yields a numpy `ndarray`, and reading multiple traces yields a generator of `ndarray`s. Generator semantics are used and the same object is reused, so if you want to cache or address trace data later, you must explicitly copy. ```python >>> f.trace[10] >>> f.trace[-2] >>> f.trace[15:45] >>> f.trace[:45:3] ``` * `header` With addressing behaviour similar to `trace`, accessing items yield header objects instead of numpy `ndarray`s. Headers are dict like objects, where keys are integers, seismic unix-style keys (in segyio.su module) and segyio enums (segyio.TraceField). Header values can be updated by assigning a dict-like to it, and keys not present on the right-hand-side of the assignment are *unmodified*. ```python >>> f.header[5] = { segyio.su.tracl: 10 } >>> f.header[5].items() >>> f.header[5][25, 37] # read multiple values at once ``` * `iline`, `xline` These modes will raise an error if the file is unstructured. They consider arguments to `[]` as the *keys* of the respective lines. Line numbers are always increasing, but can have arbitrary, uneven spacing. The valid names can be found in the `ilines` and `xlines` properties. As with traces, getting one line yields an `ndarray`, and a slice of lines yields a generator of `ndarray`s. When using slices with a step, some intermediate items might be skipped if it is not matched by the step, i.e. doing `f.line[1:10:3]` on a file with lines `[1,2,3,4,5]` is equivalent of looking up `1, 4, 7`, and finding `[1,4]`. When working with a 4D pre-stack file, the first offset is implicitly read. To access a different or a range of offsets, use comma separated indices or ranges, as such: `f.iline[120, 4]`. * `fast`, `slow` These are aliases for `iline` and `xline`, determined by how the traces are laid out. For inline sorted files, `fast` would yield `iline`. * `depth_slice` The depth slice is a horizontal, file-wide cut at a depth. The yielded values are `ndarray`s and generators-of-arrays. * `gather` The `gather` is the intersection of an inline and crossline, a vertical column of the survey, and unless a single offset is specified returns an offset x samples `ndarray`. In the presence of ranges, it returns a generator of such `ndarray`s. * `text` The `text` mode is an array of the textual headers, where `text[0]` is the standard-mandated textual header, and `1..n` are the optional extended headers. The text headers are returned as 3200-byte string-like blobs (bytes in Python 3, str in Python 2), as it is in the file. The `segyio.tools.wrap` function can create a line-oriented version of this string. * `bin` The values of the file-wide binary header with a dict-like interface. Behaves like the `header` mode, but without the indexing. ### Mode examples ### ```python >>> for line in f.iline[:2430]: ... print(np.average(line)) >>> for line in f.xline[2:10]: ... print(line) >>> for line in f.fast[::2]: ... print(np.min(line)) >>> for factor, offset in enumerate(f.iline[10, :]): ... offset *= factor print(offset) >>> f.gather[200, 241, :].shape >>> text = f.text[0] >>> type(text) # 'str' in Python 2 >>> f.trace[10] = np.zeros(len(f.samples)) ``` More examples and recipes can be found in the docstrings `help(segyio)` and the [examples](#examples) section. ## Project goals ## Segyio does necessarily attempt to be the end-all of SEG-Y interactions; rather, we aim to lower the barrier to interacting with SEG-Y files for embedding, new applications or free-standing programs. Additionally, the aim is not to support the full standard or all exotic (but standard compliant) formatted files out there. Some assumptions are made, such as: * All traces in a file are assumed to be of the same size * All samples are 4-byte floats Currently, segyio supports: * Post-stack 3D volumes, sorted with respect to two header words (generally INLINE and CROSSLINE) * Pre-stack 4D volumes, sorted with respect to three header words (generally INLINE, CROSSLINE, and OFFSET) * Unstructured data The writing functionality in segyio is largely meant to *modify* or adapt files. A file created from scratch is not necessarily a to-spec SEG-Y file, as we only necessarily write the header fields segyio needs to make sense of the geometry. It is still highly recommended that SEG-Y files are maintained and written according to specification, but segyio does not enforce this. ## Contributing ## We welcome all kinds of contributions, including code, bug reports, issues, feature requests, and documentation. The preferred way of submitting a contribution is to either make an [issue](https://github.com/Statoil/segyio/issues) on github or by forking the project on github and making a pull request. ## xarray integration ## [Alan Richardson](https://github.com/ar4) has written a great little tool for using [xarray](http://xarray.pydata.org/en/stable/) with segy files, which he demos in this [notebook](https://github.com/ar4/netcdf_segy/blob/master/notebooks/netcdf_segy.ipynb) ## Reproducing the test data ## Small SEG-Y formatted files are included in the repository for test purposes. The data is non-sensical and made to be predictable, and it is reproducible by using segyio. The tests file are located in the test-data directory. To reproduce the data file, build segyio and run the test program `make-file.py`, `make-ps-file.py`, and `make-rotated-copies.py` as such: ```python python examples/make-file.py small.sgy 50 1 6 20 25 python examples/make-ps-file.py small-ps.sgy 10 1 5 1 4 1 3 python examples/make-rotated-copies.py small.sgy ``` The small-lsb.sgy file was created by running the flip-endianness program. This program is included in the segyio source tree, but not a part of the package, and not intended for distribution and installation, only for reproducing test files. The seismic unix file small.su and small-lsb.su were created by the following commands: ```bash segyread tape=small.sgy ns=50 remap=tracr,cdp byte=189l,193l conv=1 format=1 \ > small-lsb.su suswapbytes < small.su > small-lsb.su ``` If you have have small data files with a free license, feel free to submit it to the project! ## Examples ## ### Python ### Import useful libraries: ```python import segyio import numpy as np from shutil import copyfile ``` Open segy file and inspect it: ```python filename = 'name_of_your_file.sgy' with segyio.open(filename, "r") as segyfile: # Memory map file for faster reading (especially if file is big...) segyfile.mmap() # Print binary header info print(segyfile.bin) print(segyfile.bin[segyio.BinField.Traces]) # Read headerword inline for trace 10 print(segyfile.header[10][segyio.TraceField.INLINE_3D]) # Print inline and crossline axis print(segyfile.xlines) print(segyfile.ilines) ``` Read post-stack data cube contained in segy file: ```python # Read data along first xline data = segyfile.xline[segyfile.xlines[1]] # Read data along last iline data = segyfile.iline[segyfile.ilines[-1]] # Read data along 100th time slice data = segyfile.depth_slice[100] # Read data cube data = segyio.tools.cube(filename) ``` Read pre-stack data cube contained in segy file: ```python filename = 'name_of_your_prestack_file.sgy' with segyio.open(filename, "r") as segyfile: # Print offsets print(segyfile.offset) # Read data along first iline and offset 100: data [nxl x nt] data = segyfile.iline[0, 100] # Read data along first iline and all offsets gath: data [noff x nxl x nt] data = np.asarray([np.copy(x) for x in segyfile.iline[0:1, :]]) # Read data along first 5 ilines and all offsets gath: data [noff nil x nxl x nt] data = np.asarray([np.copy(x) for x in segyfile.iline[0:5, :]]) # Read data along first xline and all offsets gath: data [noff x nil x nt] data = np.asarray([np.copy(x) for x in segyfile.xline[0:1, :]]) ``` Read and understand fairly 'unstructured' data (e.g., data sorted in common shot gathers): ```python filename = 'name_of_your_prestack_file.sgy' with segyio.open(filename, "r", ignore_geometry=True) as segyfile: segyfile.mmap() # Extract header word for all traces sourceX = segyfile.attributes(segyio.TraceField.SourceX)[:] # Scatter plot sources and receivers color-coded on their number plt.figure() sourceY = segyfile.attributes(segyio.TraceField.SourceY)[:] nsum = segyfile.attributes(segyio.TraceField.NSummedTraces)[:] plt.scatter(sourceX, sourceY, c=nsum, edgecolor='none') groupX = segyfile.attributes(segyio.TraceField.GroupX)[:] groupY = segyfile.attributes(segyio.TraceField.GroupY)[:] nstack = segyfile.attributes(segyio.TraceField.NStackedTraces)[:] plt.scatter(groupX, groupY, c=nstack, edgecolor='none') ``` Write segy file using same header of another file but multiply data by *2 ```python input_file = 'name_of_your_input_file.sgy' output_file = 'name_of_your_output_file.sgy' copyfile(input_file, output_file) with segyio.open(output_file, "r+") as src: # multiply data by 2 for i in src.ilines: src.iline[i] = 2 * src.iline[i] ``` Make segy file from sctrach ```python spec = segyio.spec() filename = 'name_of_your_file.sgy' spec = segyio.spec() file_out = 'test1.sgy' spec.sorting = 2 spec.format = 1 spec.samples = np.arange(30) spec.ilines = np.arange(10) spec.xlines = np.arange(20) with segyio.create(filename, spec) as f: # write the line itself to the file and the inline number in all this line's headers for ilno in spec.ilines: f.iline[ilno] = np.zeros( (len(spec.xlines), spec.samples), dtype=np.single) + ilno f.header.iline[ilno] = { segyio.TraceField.INLINE_3D: ilno, segyio.TraceField.offset: 0 } # then do the same for xlines for xlno in spec.xlines: f.header.xline[xlno] = { segyio.TraceField.CROSSLINE_3D: xlno, segyio.TraceField.TRACE_SAMPLE_INTERVAL: 4000 } ``` Visualize data using sibling tool [SegyViewer](https://github.com/Statoil/segyviewer): ```python from PyQt4.QtGui import QApplication import segyviewlib qapp = QApplication([]) l = segyviewlib.segyviewwidget.SegyViewWidget('filename.sgy') l.show() ``` ### MATLAB ### ``` filename='name_of_your_file.sgy' % Inspect segy Segy_struct=SegySpec(filename,189,193,1); % Read headerword inline for each trace Segy.get_header(filename,'Inline3D') %Read data along first xline data= Segy.readCrossLine(Segy_struct,Segy_struct.crossline_indexes(1)); %Read cube data=Segy.get_cube(Segy_struct); %Write segy, use same header but multiply data by *2 input_file='input_file.sgy'; output_file='output_file.sgy'; copyfile(input_file,output_file) data = Segy.get_traces(input_file); data1 = 2*data; Segy.put_traces(output_file, data1); ``` ## Common issues ## ### ImportError: libsegyio.so.1: cannot open shared object file This error shows up when the loader cannot find the core segyio library. If you've explicitly set the install prefix (with `-DCMAKE_INSTALL_PREFIX`) you must configure your loader to also look in this prefix, either with a `ld.conf.d` file or the `LD_LIBRARY_PATH` variable. If you haven't set `CMAKE_INSTALL_PREFIX`, cmake will by default install to `/usr/local`, which your loader usually knows about. On Debian based systems, the library often gets installed to `/usr/local/lib`, which the loader may not know about. See [issue #239](https://github.com/Statoil/segyio/issues/239). #### Possible solutions * Configure the loader (`sudo ldconfig` often does the trick) * Install with a different, known prefix, e.g. `-DCMAKE_INSTALL_LIBDIR=lib64` ## History ## Segyio was initially written and is maintained by [Statoil ASA](http://www.statoil.com/) as a free, simple, easy-to-use way of interacting with seismic data that can be tailored to our needs, and as contribution to the free software community. segyio-1.8.3/applications/0000775000372000037200000000000013407674361015125 5ustar travistravissegyio-1.8.3/applications/segyinfo.c0000664000372000037200000001104213407674361017112 0ustar travistravis#include #include #include #include #include #include static void printSegyTraceInfo( const char* buf ) { int cdp, tsf, xl, il; segy_get_field( buf, SEGY_TR_ENSEMBLE, &cdp ); segy_get_field( buf, SEGY_TR_SEQ_FILE, &tsf ); segy_get_field( buf, SEGY_TR_CROSSLINE, &xl ); segy_get_field( buf, SEGY_TR_INLINE, &il ); printf("cdp: %d\n", cdp ); printf("TraceSequenceFile: %d\n", tsf ); printf("Crossline3D: %d\n", xl ); printf("Inline3D: %d\n", il ); } #define minimum(x,y) ((x) < (y) ? (x) : (y)) #define maximum(x,y) ((x) > (y) ? (x) : (y)) int main(int argc, char* argv[]) { if( argc < 2 ) { puts("Missing argument, expected run signature:"); printf(" %s [mmap]\n", argv[0]); exit(1); } segy_file* fp = segy_open( argv[ 1 ], "rb" ); if( !fp ) { perror( "fopen():" ); exit( 3 ); } if( argc > 2 && strcmp( argv[ 2 ], "mmap" ) == 0 ) { int err = segy_mmap( fp ); if( err != SEGY_OK ) fputs( "Could not mmap file. Using fstream fallback.", stderr ); } int err; char header[ SEGY_BINARY_HEADER_SIZE ]; err = segy_binheader( fp, header ); if( err != 0 ) { perror( "Unable to read segy binary header:" ); exit( err ); } const int format = segy_format( header ); const int samples = segy_samples( header ); const long trace0 = segy_trace0( header ); const int trace_bsize = segy_trace_bsize( samples ); int extended_headers; err = segy_get_bfield( header, SEGY_BIN_EXT_HEADERS, &extended_headers ); if( err != 0 ) { perror( "Can't read 'extended headers' field from binary header" ); exit( err ); } int traces; err = segy_traces( fp, &traces, trace0, trace_bsize ); if( err != 0 ) { perror( "Could not determine traces" ); exit( err ); } printf( "Sample format: %d\n", format ); printf( "Samples per trace: %d\n", samples ); printf( "Traces: %d\n", traces ); printf("Extended text header count: %d\n", extended_headers ); puts(""); char traceh[ SEGY_TRACE_HEADER_SIZE ]; err = segy_traceheader( fp, 0, traceh, trace0, trace_bsize ); if( err != 0 ) { perror( "Unable to read trace 0:" ); exit( err ); } puts("Info from first trace:"); printSegyTraceInfo( traceh ); err = segy_traceheader( fp, 1, traceh, trace0, trace_bsize ); if( err != 0 ) { perror( "Unable to read trace 1:" ); exit( err ); } puts(""); puts("Info from second trace:"); printSegyTraceInfo( traceh ); clock_t start = clock(); float* trbuf = malloc( sizeof( float ) * trace_bsize ); float minval = FLT_MAX; float maxval = FLT_MIN; int min_sample_count = 999999999; int max_sample_count = 0; for( int i = 0; i < traces; ++i ) { err = segy_traceheader( fp, i, traceh, trace0, trace_bsize ); if( err != 0 ) { perror( "Unable to read trace" ); exit( err ); } int sample_count; err = segy_get_field( traceh, SEGY_TR_SAMPLE_COUNT, &sample_count ); if( err != 0 ) { fprintf( stderr, "Invalid trace header field: %d\n", SEGY_TR_SAMPLE_COUNT ); exit( err ); } min_sample_count = minimum( sample_count, min_sample_count ); max_sample_count = maximum( sample_count, max_sample_count ); err = segy_readtrace( fp, i, trbuf, trace0, trace_bsize ); if( err != 0 ) { fprintf( stderr, "Unable to read trace: %d\n", i ); exit( err ); } segy_to_native( format, samples, trbuf ); for( int j = 0; j < samples; ++j ) { minval = minimum( trbuf[ j ], minval ); maxval = maximum( trbuf[ j ], maxval ); } } free( trbuf ); puts(""); puts("Info from last trace:"); err = segy_traceheader( fp, traces - 1, traceh, trace0, trace_bsize ); if( err != 0 ) { perror( "Unable to read trace." ); exit( err ); } printSegyTraceInfo( traceh ); puts(""); printf("Min sample count: %d\n", min_sample_count); printf("Max sample count: %d\n", max_sample_count); printf("Min sample value: %f\n", minval ); printf("Max sample value: %f\n", maxval ); puts(""); clock_t diff = clock() - start; printf("Read all trace headers in: %.2f s\n", (double) diff / CLOCKS_PER_SEC); segy_close( fp ); return 0; } segyio-1.8.3/applications/apputils.h0000664000372000037200000000055113407674361017140 0ustar travistravis#ifndef SEGYIO_APPUTILS_H #define SEGYIO_APPUTILS_H int errmsg( int errcode, const char* msg ); int errmsg2( int errcode, const char* prelude, const char* msg ); int parseint( const char* str, int* x ); int bfield( const char* header, int field ); int trfield( const char* header, int field ); int printversion( const char* name ); #endif //SEGYIO_APPUTILS_H segyio-1.8.3/applications/segyio-crop.c0000664000372000037200000004501513407674361017536 0ustar travistravis#include #include #include #include #include #include #include #include "apputils.c" #include static int help() { puts( "Usage: segyio-crop [OPTION]... SRC DST\n" "Copy a sub cube from SRC to DST\n" "\n" "-i, --iline-begin=LINE inline to copy from\n" "-I, --iline-end=LINE inline to copy to (inclusive)\n" "-x, --xline-begin=LINE crossline to copy from\n" "-X, --xline-end=LINE crossline to copy to (inclusive)\n" " --inline-begin alias to --iline-begin\n" " --crossline-begin alias to --xline-begin\n" "-s, --sample-begin=TIME measurement to copy from\n" "-S, --sample-end=TIME measurement to copy to (inclusive)\n" "-f --format=FORMAT override sample format. defaults to " " inferring from the binary header.\n" " formats: ibm ieee short long char\n" "-b, --il inline header word byte offset\n" "-B, --xl crossline header word byte offset\n" "-v, --verbose increase verbosity\n" " --version output version information and exit\n" " --help display this help and exit\n" "\n" "If no begin/end options are specified, this program is\n" "essentially a copy. If a begin option is omitted, the program\n" "copies from the start. If an end option is omitted, the program\n" "copies until the end.\n" ); return 0; } struct delay { int delay; int skip; int len; }; static struct delay delay_recording_time( const char* trheader, int sbeg, int send, int dt, int samples ) { long long t0 = trfield( trheader, SEGY_TR_DELAY_REC_TIME ); int trdt = trfield( trheader, SEGY_TR_SAMPLE_INTER ); if( trdt ) dt = trdt; /* * begin/end not specified - copy the full trace, so dont try to identify * the sub trace */ struct delay d = { t0, 0, samples }; if( sbeg < 0 && send == INT_MAX ) return d; /* determine what to cut off at the start of the trace */ if( sbeg - t0 > 0 ) { long long skip = ((sbeg - t0) * 1000) / dt; d.delay = t0 + ((skip * dt) / 1000 ); d.skip = skip; d.len -= d.skip; } /* determine what to cut off at the end of the trace */ if( (long long)send * 1000 < (t0 * 1000) + (samples * dt) ) { long long t0us = t0 * 1000; long long sendus = (long long)send * 1000; d.len -= (t0us + ((samples - 1) * dt) - sendus) / dt; } return d; } static int valid_trfield( int x ) { switch( x ) { case SEGY_TR_SEQ_LINE: case SEGY_TR_SEQ_FILE: case SEGY_TR_FIELD_RECORD: case SEGY_TR_NUMBER_ORIG_FIELD: case SEGY_TR_ENERGY_SOURCE_POINT: case SEGY_TR_ENSEMBLE: case SEGY_TR_NUM_IN_ENSEMBLE: case SEGY_TR_TRACE_ID: case SEGY_TR_SUMMED_TRACES: case SEGY_TR_STACKED_TRACES: case SEGY_TR_DATA_USE: case SEGY_TR_OFFSET: case SEGY_TR_RECV_GROUP_ELEV: case SEGY_TR_SOURCE_SURF_ELEV: case SEGY_TR_SOURCE_DEPTH: case SEGY_TR_RECV_DATUM_ELEV: case SEGY_TR_SOURCE_DATUM_ELEV: case SEGY_TR_SOURCE_WATER_DEPTH: case SEGY_TR_GROUP_WATER_DEPTH: case SEGY_TR_ELEV_SCALAR: case SEGY_TR_SOURCE_GROUP_SCALAR: case SEGY_TR_SOURCE_X: case SEGY_TR_SOURCE_Y: case SEGY_TR_GROUP_X: case SEGY_TR_GROUP_Y: case SEGY_TR_COORD_UNITS: case SEGY_TR_WEATHERING_VELO: case SEGY_TR_SUBWEATHERING_VELO: case SEGY_TR_SOURCE_UPHOLE_TIME: case SEGY_TR_GROUP_UPHOLE_TIME: case SEGY_TR_SOURCE_STATIC_CORR: case SEGY_TR_GROUP_STATIC_CORR: case SEGY_TR_TOT_STATIC_APPLIED: case SEGY_TR_LAG_A: case SEGY_TR_LAG_B: case SEGY_TR_DELAY_REC_TIME: case SEGY_TR_MUTE_TIME_START: case SEGY_TR_MUTE_TIME_END: case SEGY_TR_SAMPLE_COUNT: case SEGY_TR_SAMPLE_INTER: case SEGY_TR_GAIN_TYPE: case SEGY_TR_INSTR_GAIN_CONST: case SEGY_TR_INSTR_INIT_GAIN: case SEGY_TR_CORRELATED: case SEGY_TR_SWEEP_FREQ_START: case SEGY_TR_SWEEP_FREQ_END: case SEGY_TR_SWEEP_LENGTH: case SEGY_TR_SWEEP_TYPE: case SEGY_TR_SWEEP_TAPERLEN_START: case SEGY_TR_SWEEP_TAPERLEN_END: case SEGY_TR_TAPER_TYPE: case SEGY_TR_ALIAS_FILT_FREQ: case SEGY_TR_ALIAS_FILT_SLOPE: case SEGY_TR_NOTCH_FILT_FREQ: case SEGY_TR_NOTCH_FILT_SLOPE: case SEGY_TR_LOW_CUT_FREQ: case SEGY_TR_HIGH_CUT_FREQ: case SEGY_TR_LOW_CUT_SLOPE: case SEGY_TR_HIGH_CUT_SLOPE: case SEGY_TR_YEAR_DATA_REC: case SEGY_TR_DAY_OF_YEAR: case SEGY_TR_HOUR_OF_DAY: case SEGY_TR_MIN_OF_HOUR: case SEGY_TR_SEC_OF_MIN: case SEGY_TR_TIME_BASE_CODE: case SEGY_TR_WEIGHTING_FAC: case SEGY_TR_GEOPHONE_GROUP_ROLL1: case SEGY_TR_GEOPHONE_GROUP_FIRST: case SEGY_TR_GEOPHONE_GROUP_LAST: case SEGY_TR_GAP_SIZE: case SEGY_TR_OVER_TRAVEL: case SEGY_TR_CDP_X: case SEGY_TR_CDP_Y: case SEGY_TR_INLINE: case SEGY_TR_CROSSLINE: case SEGY_TR_SHOT_POINT: case SEGY_TR_SHOT_POINT_SCALAR: case SEGY_TR_MEASURE_UNIT: case SEGY_TR_TRANSDUCTION_MANT: case SEGY_TR_TRANSDUCTION_EXP: case SEGY_TR_TRANSDUCTION_UNIT: case SEGY_TR_DEVICE_ID: case SEGY_TR_SCALAR_TRACE_HEADER: case SEGY_TR_SOURCE_TYPE: case SEGY_TR_SOURCE_ENERGY_DIR_MANT: case SEGY_TR_SOURCE_ENERGY_DIR_EXP: case SEGY_TR_SOURCE_MEASURE_MANT: case SEGY_TR_SOURCE_MEASURE_EXP: case SEGY_TR_SOURCE_MEASURE_UNIT: case SEGY_TR_UNASSIGNED1: case SEGY_TR_UNASSIGNED2: return 1; default: return 0; } } #define TRHSIZE SEGY_TRACE_HEADER_SIZE #define BINSIZE SEGY_BINARY_HEADER_SIZE #define TEXTSIZE SEGY_TEXT_HEADER_SIZE struct options { int ibeg, iend; int xbeg, xend; int sbeg, send; int format; int il, xl; char* src; char* dst; int verbosity; int version, help; const char* errmsg; }; static struct options parse_options( int argc, char** argv ) { struct options opts; opts.ibeg = -1, opts.iend = INT_MAX; opts.xbeg = -1, opts.xend = INT_MAX; opts.sbeg = -1, opts.send = INT_MAX; opts.format = 0; opts.il = SEGY_TR_INLINE, opts.xl = SEGY_TR_CROSSLINE; opts.verbosity = 0; opts.version = 0, opts.help = 0; opts.errmsg = NULL; struct options opthelp, optversion; opthelp.help = 1, opthelp.errmsg = NULL; optversion.version = 1, optversion.errmsg = NULL; static struct option long_options[] = { { "iline-begin", required_argument, 0, 'i' }, { "iline-end", required_argument, 0, 'I' }, { "inline-begin", required_argument, 0, 'i' }, { "inline-end", required_argument, 0, 'I' }, { "xline-begin", required_argument, 0, 'x' }, { "xline-end", required_argument, 0, 'X' }, { "crossline-begin", required_argument, 0, 'x' }, { "crossline-end", required_argument, 0, 'X' }, { "sample-begin", required_argument, 0, 's' }, { "sample-end", required_argument, 0, 'S' }, { "format", required_argument, 0, 'f' }, { "il", required_argument, 0, 'b' }, { "xl", required_argument, 0, 'B' }, { "verbose", no_argument, 0, 'v' }, { "version", no_argument, 0, 'V' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; static const char* parsenum_errmsg[] = { "", "num must be an integer", "num must be non-negative" }; opterr = 1; while( true ) { int option_index = 0; int c = getopt_long( argc, argv, "vi:I:x:X:f:s:S:b:B:", long_options, &option_index ); if( c == -1 ) break; int ret; switch( c ) { case 0: break; case 'h': return opthelp; case 'V': return optversion; case 'v': ++opts.verbosity; break; case 'i': ret = parseint( optarg, &opts.ibeg ); if( ret == 0 ) break; opts.errmsg = parsenum_errmsg[ ret ]; return opts; case 'I': ret = parseint( optarg, &opts.iend ); if( ret == 0 ) break; opts.errmsg = parsenum_errmsg[ ret ]; return opts; case 'x': ret = parseint( optarg, &opts.xbeg ); if( ret == 0 ) break; opts.errmsg = parsenum_errmsg[ ret ]; return opts; case 'X': ret = parseint( optarg, &opts.xend ); if( ret == 0 ) break; opts.errmsg = parsenum_errmsg[ ret ]; return opts; case 'f': if( strcmp( optarg, "ibm" ) == 0 ) opts.format = SEGY_IBM_FLOAT_4_BYTE; if( strcmp( optarg, "ieee" ) == 0 ) opts.format = SEGY_IEEE_FLOAT_4_BYTE; if( strcmp( optarg, "short" ) == 0 ) opts.format = SEGY_SIGNED_SHORT_2_BYTE; if( strcmp( optarg, "long" ) == 0 ) opts.format = SEGY_SIGNED_INTEGER_4_BYTE; if( strcmp( optarg, "char" ) == 0 ) opts.format = SEGY_SIGNED_CHAR_1_BYTE; if( opts.format == 0 ) { opts.errmsg = "invalid format argument. valid formats: " "ibm ieee short long char"; return opts; } break; case 's': ret = parseint( optarg, &opts.sbeg ); if( ret == 0 ) break; opts.errmsg = parsenum_errmsg[ ret ]; return opts; case 'S': ret = parseint( optarg, &opts.send ); if( ret == 0 ) break; opts.errmsg = parsenum_errmsg[ ret ]; return opts; case 'b': ret = parseint( optarg, &opts.il ); if( ret == 0 ) break; opts.errmsg = parsenum_errmsg[ ret ]; return opts; case 'B': ret = parseint( optarg, &opts.xl ); if( ret == 0 ) break; opts.errmsg = parsenum_errmsg[ ret ]; return opts; default: opthelp.errmsg = ""; return opthelp; } } if( argc - optind != 2 ) { errmsg( 0, "Wrong number of files" ); return opthelp; } opts.src = argv[ optind + 0 ]; opts.dst = argv[ optind + 1 ]; return opts; } int main( int argc, char** argv ) { struct options opts = parse_options( argc, argv ); if( opts.help ) exit( help() + (opts.errmsg ? 2 : 0) ); if( opts.version ) exit( printversion( "segyio-crop" ) ); if( opts.errmsg ) exit( errmsg( EINVAL, opts.errmsg ) ); int ibeg = opts.ibeg; int iend = opts.iend; int xbeg = opts.xbeg; int xend = opts.xend; int sbeg = opts.sbeg; int send = opts.send; int il = opts.il; int xl = opts.xl; int verbosity = opts.verbosity; if( !valid_trfield( il ) ) exit( errmsg( -3, "Invalid inline byte offset" ) ); if( !valid_trfield( xl ) ) exit( errmsg( -3, "Invalid crossline byte offset" ) ); if( ibeg > iend ) exit( errmsg( -4, "Invalid iline interval - file would be empty" ) ); if( xbeg > xend ) exit( errmsg( -4, "Invalid xline interval - file would be empty" ) ); if( sbeg > send ) exit( errmsg( -4, "Invalid sample interval - file would be empty" ) ); char textheader[ TEXTSIZE ] = { 0 }; char binheader[ BINSIZE ] = { 0 }; char trheader[ TEXTSIZE ] = { 0 }; if( !strcmp( opts.src, opts.dst ) ) exit( errmsg( 1, "segyio-crop: " "output file must be different from input file" ) ); FILE* src = fopen( opts.src, "rb" ); if( !src ) exit( errmsg2( errno, "Unable to open src", strerror( errno ) ) ); FILE* dst = fopen( opts.dst, "wb" ); if( !dst ) exit( errmsg2( errno, "Unable to open dst", strerror( errno ) ) ); /* copy the textual and binary headers */ if( verbosity > 0 ) puts( "Copying text header" ); int sz; sz = fread( textheader, TEXTSIZE, 1, src ); if( sz != 1 ) exit( errmsg2( errno, "Unable to read text header", strerror( errno ) ) ); sz = fwrite( textheader, TEXTSIZE, 1, dst ); if( sz != 1 ) exit( errmsg2( errno, "Unable to write text header", strerror( errno ) ) ); if( verbosity > 0 ) puts( "Copying binary header" ); sz = fread( binheader, BINSIZE, 1, src ); if( sz != 1 ) exit( errmsg2( errno, "Unable to read binary header", strerror( errno ) ) ); sz = fwrite( binheader, BINSIZE, 1, dst ); if( sz != 1 ) exit( errmsg2( errno, "Unable to write binary header", strerror( errno ) ) ); int ext_headers = bfield( binheader, SEGY_BIN_EXT_HEADERS ); if( ext_headers < 0 ) exit( errmsg( -1, "Malformed binary header" ) ); for( int i = 0; i < ext_headers; ++i ) { if( verbosity > 0 ) puts( "Copying extended text header" ); sz = fread( textheader, TEXTSIZE, 1, src ); if( sz != 1 ) exit( errmsg2( errno, "Unable to read ext text header", strerror( errno ) ) ); sz = fwrite( textheader, TEXTSIZE, 1, dst ); if( sz != 1 ) exit( errmsg2( errno, "Unable to write ext text header", strerror( errno ) ) ); } if( verbosity > 2 ) puts( "Computing samples-per-trace" ); const int bindt = bfield( binheader, SEGY_BIN_INTERVAL ); const int src_samples = bfield( binheader, SEGY_BIN_SAMPLES ); if( src_samples < 0 ) exit( errmsg( -2, "Could not determine samples per trace" ) ); if( verbosity > 2 ) printf( "Found %d samples per trace\n", src_samples ); int format = opts.format ? opts.format : segy_format( binheader ); /* check that the format we get from the binary header isn't garbage */ switch( format ) { /* all good */ case SEGY_IBM_FLOAT_4_BYTE: case SEGY_SIGNED_INTEGER_4_BYTE: case SEGY_SIGNED_SHORT_2_BYTE: case SEGY_FIXED_POINT_WITH_GAIN_4_BYTE: case SEGY_IEEE_FLOAT_4_BYTE: case SEGY_SIGNED_CHAR_1_BYTE: break; /* * assume this header field is just not set, silently fall back * to 4-byte floats */ case 0: format = SEGY_IBM_FLOAT_4_BYTE; break; case SEGY_NOT_IN_USE_1: case SEGY_NOT_IN_USE_2: default: errmsg( 1, "sample format field is garbage. " "falling back to 4-byte float. " "override with --format" ); format = SEGY_IBM_FLOAT_4_BYTE; } if( verbosity > 1 && !opts.format ) { static const char* samplefmts[] = { "", "ibm", "long", "short", "fixed-point 4-byte float", "ieee", "invalid", "invalid", "char", }; printf( "Inferred sample format %s\n", samplefmts[ format ] ); } const int trace_bsize = segy_trsize( format, src_samples ); const int elemsize = trace_bsize / src_samples; if( verbosity > 2 ) printf( "Found %d bytes per trace\n", trace_bsize ); void* trace = malloc( trace_bsize ); if( verbosity > 0 ) puts( "Copying traces" ); long long traces = 0; while( true ) { sz = fread( trheader, TRHSIZE, 1, src ); if( sz != 1 && feof( src ) ) break; if( sz != 1 && ferror( src ) ) exit( errmsg( ferror( src ), "Unable to read trace header" ) ); int ilno = trfield( trheader, il ); int xlno = trfield( trheader, xl ); /* outside copy interval - skip this trace */ if( ilno < ibeg || ilno > iend || xlno < xbeg || xlno > xend ) { fseek( src, elemsize * src_samples, SEEK_CUR ); continue; } sz = fread( trace, elemsize, src_samples, src ); if( sz != src_samples ) exit( errmsg2( errno, "Unable to read trace", strerror( errno ) ) ); /* figure out how to crop the trace */ struct delay d = delay_recording_time( trheader, sbeg, send, bindt, src_samples ); segy_set_field( trheader, SEGY_TR_SAMPLE_COUNT, d.len ); segy_set_field( trheader, SEGY_TR_DELAY_REC_TIME, d.delay ); segy_set_bfield( binheader, SEGY_BIN_SAMPLES, d.len ); if( verbosity > 2 ) printf( "Copying trace %lld\n", traces ); sz = fwrite( trheader, TRHSIZE, 1, dst ); if( sz != 1 ) exit( errmsg2( errno, "Unable to write trace header", strerror( errno ) ) ); sz = fwrite( (char*)trace + elemsize * d.skip, elemsize, d.len, dst ); if( sz != d.len ) exit( errmsg2( errno, "Unable to write trace", strerror( errno ) ) ); ++traces; } fseek( dst, SEGY_TEXT_HEADER_SIZE, SEEK_SET ); sz = fwrite( binheader, BINSIZE, 1, dst ); if( sz != 1 ) exit( errmsg2( errno, "Unable to write binary header", strerror( errno ) ) ); if( verbosity > 0 ) printf( "Copied %lld traces\n", traces ); if( !traces ) fprintf( stderr, "segyio-crop: no traces copied\n" ); free( trace ); fclose( dst ); fclose( src ); } segyio-1.8.3/applications/segyio-catr.c0000664000372000037200000006344413407674361017532 0ustar travistravis#include #include #include #include #include #include #include #include "apputils.c" #define TRHSIZE SEGY_TRACE_HEADER_SIZE #define BINSIZE SEGY_BINARY_HEADER_SIZE static const int fields[] = { SEGY_TR_SEQ_LINE , SEGY_TR_SEQ_FILE , SEGY_TR_FIELD_RECORD , SEGY_TR_NUMBER_ORIG_FIELD , SEGY_TR_ENERGY_SOURCE_POINT , SEGY_TR_ENSEMBLE , SEGY_TR_NUM_IN_ENSEMBLE , SEGY_TR_TRACE_ID , SEGY_TR_SUMMED_TRACES , SEGY_TR_STACKED_TRACES , SEGY_TR_DATA_USE , SEGY_TR_OFFSET , SEGY_TR_RECV_GROUP_ELEV , SEGY_TR_SOURCE_SURF_ELEV , SEGY_TR_SOURCE_DEPTH , SEGY_TR_RECV_DATUM_ELEV , SEGY_TR_SOURCE_DATUM_ELEV , SEGY_TR_SOURCE_WATER_DEPTH , SEGY_TR_GROUP_WATER_DEPTH , SEGY_TR_ELEV_SCALAR , SEGY_TR_SOURCE_GROUP_SCALAR , SEGY_TR_SOURCE_X , SEGY_TR_SOURCE_Y , SEGY_TR_GROUP_X , SEGY_TR_GROUP_Y , SEGY_TR_COORD_UNITS , SEGY_TR_WEATHERING_VELO , SEGY_TR_SUBWEATHERING_VELO , SEGY_TR_SOURCE_UPHOLE_TIME , SEGY_TR_GROUP_UPHOLE_TIME , SEGY_TR_SOURCE_STATIC_CORR , SEGY_TR_GROUP_STATIC_CORR , SEGY_TR_TOT_STATIC_APPLIED , SEGY_TR_LAG_A , SEGY_TR_LAG_B , SEGY_TR_DELAY_REC_TIME , SEGY_TR_MUTE_TIME_START , SEGY_TR_MUTE_TIME_END , SEGY_TR_SAMPLE_COUNT , SEGY_TR_SAMPLE_INTER , SEGY_TR_GAIN_TYPE , SEGY_TR_INSTR_GAIN_CONST , SEGY_TR_INSTR_INIT_GAIN , SEGY_TR_CORRELATED , SEGY_TR_SWEEP_FREQ_START , SEGY_TR_SWEEP_FREQ_END , SEGY_TR_SWEEP_LENGTH , SEGY_TR_SWEEP_TYPE , SEGY_TR_SWEEP_TAPERLEN_START , SEGY_TR_SWEEP_TAPERLEN_END , SEGY_TR_TAPER_TYPE , SEGY_TR_ALIAS_FILT_FREQ , SEGY_TR_ALIAS_FILT_SLOPE , SEGY_TR_NOTCH_FILT_FREQ , SEGY_TR_NOTCH_FILT_SLOPE , SEGY_TR_LOW_CUT_FREQ , SEGY_TR_HIGH_CUT_FREQ , SEGY_TR_LOW_CUT_SLOPE , SEGY_TR_HIGH_CUT_SLOPE , SEGY_TR_YEAR_DATA_REC , SEGY_TR_DAY_OF_YEAR , SEGY_TR_HOUR_OF_DAY , SEGY_TR_MIN_OF_HOUR , SEGY_TR_SEC_OF_MIN , SEGY_TR_TIME_BASE_CODE , SEGY_TR_WEIGHTING_FAC , SEGY_TR_GEOPHONE_GROUP_ROLL1 , SEGY_TR_GEOPHONE_GROUP_FIRST , SEGY_TR_GEOPHONE_GROUP_LAST , SEGY_TR_GAP_SIZE , SEGY_TR_OVER_TRAVEL , SEGY_TR_CDP_X , SEGY_TR_CDP_Y , SEGY_TR_INLINE , SEGY_TR_CROSSLINE , SEGY_TR_SHOT_POINT , SEGY_TR_SHOT_POINT_SCALAR , SEGY_TR_MEASURE_UNIT , SEGY_TR_TRANSDUCTION_MANT , SEGY_TR_TRANSDUCTION_EXP , SEGY_TR_TRANSDUCTION_UNIT , SEGY_TR_DEVICE_ID , SEGY_TR_SCALAR_TRACE_HEADER , SEGY_TR_SOURCE_TYPE , SEGY_TR_SOURCE_ENERGY_DIR_MANT , SEGY_TR_SOURCE_ENERGY_DIR_EXP , SEGY_TR_SOURCE_MEASURE_MANT , SEGY_TR_SOURCE_MEASURE_EXP , SEGY_TR_SOURCE_MEASURE_UNIT , SEGY_TR_UNASSIGNED1 , SEGY_TR_UNASSIGNED2 }; static const char* su[91] = { "tracl" , "tracr" , "fldr" , "tracf" , "ep" , "cdp" , "cdpt" , "trid" , "nvs" , "nhs" , "duse" , "offset" , "gelev" , "selev" , "sdepth" , "gdel" , "sdel" , "swdep" , "gwdep" , "scalel" , "scalco" , "sx" , "sy" , "gx" , "gy" , "counit" , "wevel" , "swevel" , "sut" , "gut" , "sstat" , "gstat" , "tstat" , "laga" , "lagb" , "delrt" , "muts" , "mute" , "ns" , "dt" , "gain" , "igc" , "igi" , "corr" , "sfs" , "sfe" , "slen" , "styp" , "stat" , "stae" , "tatyp" , "afilf" , "afils" , "nofilf" , "nofils" , "lcf" , "hcf" , "lcs" , "hcs" , "year" , "day" , "hour" , "minute" , "sec" , "timbas" , "trwf" , "grnors" , "grnofr" , "grnlof" , "gaps" , "otrav" , "cdpx" , "cdpy" , "iline" , "xline" , "sp" , "scalsp" , "trunit" , "tdcm" , "tdcp" , "tdunit" , "triden" , "sctrh" , "stype" , "sedm" , "sede" , "smm" , "sme" , "smunit" , "uint1" , "uint2" }; static const char* segynames[91] = { "SEQ_LINE" , "SEQ_FILE" , "FIELD_RECORD" , "NUMBER_ORIG_FIELD" , "ENERGY_SOURCE_POINT" , "ENSEMBLE" , "NUM_IN_ENSEMBLE" , "TRACE_ID" , "SUMMED_TRACES" , "STACKED_TRACES" , "DATA_USE" , "OFFSET" , "RECV_GROUP_ELEV" , "SOURCE_SURF_ELEV" , "SOURCE_DEPTH" , "RECV_DATUM_ELEV" , "SOURCE_DATUM_ELEV" , "SOURCE_WATER_DEPTH" , "GROUP_WATER_DEPTH" , "ELEV_SCALAR" , "SOURCE_GROUP_SCALAR" , "SOURCE_X" , "SOURCE_Y" , "GROUP_X" , "GROUP_Y" , "COORD_UNITS" , "WEATHERING_VELO" , "SUBWEATHERING_VELO" , "SOURCE_UPHOLE_TIME" , "GROUP_UPHOLE_TIME" , "SOURCE_STATIC_CORR" , "GROUP_STATIC_CORR" , "TOT_STATIC_APPLIED" , "LAG_A" , "LAG_B" , "DELAY_REC_TIME" , "MUTE_TIME_START" , "MUTE_TIME_END" , "SAMPLE_COUNT" , "SAMPLE_INTER" , "GAIN_TYPE" , "INSTR_GAIN_CONST" , "INSTR_INIT_GAIN" , "CORRELATED" , "SWEEP_FREQ_START" , "SWEEP_FREQ_END" , "SWEEP_LENGTH" , "SWEEP_TYPE" , "SWEEP_TAPERLEN_START", "SWEEP_TAPERLEN_END" , "TAPER_TYPE" , "ALIAS_FILT_FREQ" , "ALIAS_FILT_SLOPE" , "NOTCH_FILT_FREQ" , "NOTCH_FILT_SLOPE" , "LOW_CUT_FREQ" , "HIGH_CUT_FREQ" , "LOW_CUT_SLOPE" , "HIGH_CUT_SLOPE" , "YEAR_DATA_REC" , "DAY_OF_YEAR" , "HOUR_OF_DAY" , "MIN_OF_HOUR" , "SEC_OF_MIN" , "TIME_BASE_CODE" , "WEIGHTING_FAC" , "GEOPHONE_GROUP_ROLL1", "GEOPHONE_GROUP_FIRST", "GEOPHONE_GROUP_LAST" , "GAP_SIZE" , "OVER_TRAVEL" , "CDP_X" , "CDP_Y" , "INLINE" , "CROSSLINE" , "SHOT_POINT" , "SHOT_POINT_SCALAR" , "MEASURE_UNIT" , "TRANSDUCTION_MANT" , "TRANSDUCTION_EXP" , "TRANSDUCTION_UNIT" , "DEVICE_ID" , "SCALAR_TRACE_HEADER" , "SOURCE_TYPE" , "SOURCE_ENERGY_DIR_MA", "SOURCE_ENERGY_DIR_EX", "SOURCE_MEASURE_MANT" , "SOURCE_MEASURE_EXP" , "SOURCE_MEASURE_UNIT" , "UNASSIGNED1" , "UNASSIGNED2" }; static const char* desc[91] = { "Trace sequence number within line" , "Trace sequence number within SEG Y file" , "Original field record number" , "Trace number within the original field record" , "Energy source point number" , "Ensemble number" , "Trace number within the ensemble" , "Trace identification code" , "Number of vertically summed traces yielding this trace" , "Number of horizontally stacked traces yielding this trace" , "Data use" , "Distance from center of the source point to the center of the " "receiver group" , "Receiver group elevation" , "Surface elevation at source" , "Source depth below surface" , "Datum elevation at receiver group" , "Datum elevation at source" , "Water depth at source" , "Water depth at group" , "Scalar to be applied to all elevations and depths specified in Trace " "Header bytes 41-68 to give the real value" , "Scalar to be applied to all coordinates specified in Trace Header " "bytes 73-88 and to bytes Trace Header 181-188 to give the real value" , "Source coordinate - X" , "Source coordinate - Y" , "Group coordinate - X" , "Group coordinate - Y" , "Coordinate units" , "Weathering velocity" , "Subweathering velocity" , "Uphole time at source in milliseconds" , "Uphole time at group in milliseconds" , "Source static correction in milliseconds" , "Group static correction in milliseconds" , "Total static applied in milliseconds" , "Lag time A" , "Lag Time B" , "Delay recording time" , "Mute time — Start time in milliseconds" , "Mute time — End time in milliseconds" , "Number of samples in this trace" , "Sample interval in microseconds (μs) for this trace" , "Gain type of field instruments" , "Instrument gain constant (dB)" , "Instrument early or initial gain (dB)" , "Correlated" , "Sweep frequency at start (Hz)" , "Sweep frequency at end (Hz)" , "Sweep length in milliseconds" , "Sweep type" , "Sweep trace taper length at start in milliseconds" , "Sweep trace taper length at end in milliseconds" , "Taper type" , "Alias filter frequency (Hz), if used" , "Alias filter slope (dB/octave)" , "Notch filter frequency (Hz), if used" , "Notch filter slope (dB/octave)" , "Low-cut frequency (Hz), if used" , "High-cut frequency (Hz), if used" , "Low-cut slope (dB/octave)" , "High-cut slope (dB/octave)" , "Year data recorded" , "Day of year" , "Hour of day (24 hour clock)" , "Minute of hour" , "Second of minute" , "Time basis code" , "Trace weighting factor" , "Geophone group number of roll switch position one" , "Geophone group number of trace number one within original field record", "Geophone group number of last trace within original field record" , "Gap size (total number of groups dropped)" , "Over travel associated with taper at beginning or end of line" , "X coordinate of ensemble (CDP) position of this trace" , "Y coordinate of ensemble (CDP) position of this trace" , "Inline number" , "Crossline number" , "Shotpoint number" , "Scalar to be applied to the shotpoint number in Trace Header bytes " "197-200 to give the real value" , "Trace value measurement unit" , "Transduction Constant (mantissa)" , "Transduction Constant (power of ten exponent)" , "Transduction Units" , "Device/Trace Identifier" , "Scalar to be applied to times specified in Trace Header bytes 95-114 " "to give the true time value in milliseconds" , "Source Type/Orientation" , "Source Energy Direction with respect to the source orientation " "(vertical and crossline)" , "Source Energy Direction with respect to the source orientation " "(inline)" , "Source Measurement (mantissa)" , "Source Measurement (power of ten exponent)" , "Source Measurement Unit" , "Unassigned 1" , "Unassigned 2" }; static int help() { puts( "Usage: segyio-catr [OPTION]... FILE\n" "Print specific trace headers from FILE\n" "\n" "-t, --trace=NUMBER trace to print\n" "-r, --range START STOP STEP range of traces to print\n" "-f, --format=FORMAT override sample format. defaults to inferring\n" " from the binary header.\n" " formats: ibm ieee short long char\n" "-s, --strict fail on unreadable tracefields\n" "-S, --non-strict don't fail on unreadable tracefields\n" " this is the default behaviour\n" "-n, --nonzero only print fields with non-zero values\n" "-d, --description print with byte offset and field description\n" "-k, --segyio print with segyio tracefield names\n" "-v, --verbose increase verbosity\n" " --version output version information and exit\n" " --help display this help and exit\n" "\n" "the -r flag takes up to three values: start, stop, step\n" "where all values are defaulted to zero\n" "flags -r and -t can be used multiple times\n" ); return 0; } typedef struct { int start, stop, step; } range; struct options { char* src; range* r; int rsize; int format; int verbosity; int version, help; int strict, labels; int nonzero, description; const char* errmsg; }; enum { su_labels, segyio_labels } label_ids; static range fill_range( range r, int field, int val ) { switch( field ) { case 0: r.start = val; return r; case 1: r.stop = val; return r; case 2: r.step = val; return r; default: exit( 12 ); } } static struct options parse_options( int argc, char** argv ){ int rallocsize = 32; struct options opts; opts.rsize = 0; opts.r = calloc( sizeof( range ), rallocsize ); opts.format = 0; opts.verbosity = 0; opts.nonzero = 0; opts.description = 0; opts.version = 0; opts.help = 0; opts.strict = 0; opts.labels = su_labels; opts.errmsg = NULL; static struct option long_options[] = { { "trace", required_argument, 0, 't' }, { "range", required_argument, 0, 'r' }, { "format", required_argument, 0, 'f' }, { "segyio", no_argument, 0, 'k' }, { "strict", no_argument, 0, 's' }, { "non-strict", no_argument, 0, 'S' }, { "description", no_argument, 0, 'd' }, { "nonzero", no_argument, 0, 'n' }, { "verbose", no_argument, 0, 'v' }, { "version", no_argument, 0, 'V' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0,} }; static const char* parsenum_errmsg[] = { "", "num must be an integer", "num must be non-negative" }; opterr = 1; while( true ) { int option_index = 0; int c = getopt_long( argc, argv, "sSkdnvt:r:f:", long_options, &option_index ); if( c == -1 ) break; int ret; switch( c ) { case 0: break; case 'h': opts.help = 1; return opts; case 'V': opts.version = 1; return opts; case 'v': ++opts.verbosity; break; case 's': opts.strict = 1; break; case 'S': opts.strict = 0; break; case 'd': opts.description = 1; break; case 'n': opts.nonzero = 1; break; case 'k': opts.labels = segyio_labels; break; case 'f': if( strcmp( optarg, "ibm" ) == 0 ) opts.format = SEGY_IBM_FLOAT_4_BYTE; if( strcmp( optarg, "ieee" ) == 0 ) opts.format = SEGY_IEEE_FLOAT_4_BYTE; if( strcmp( optarg, "short" ) == 0 ) opts.format = SEGY_SIGNED_SHORT_2_BYTE; if( strcmp( optarg, "long" ) == 0 ) opts.format = SEGY_SIGNED_INTEGER_4_BYTE; if( strcmp( optarg, "char" ) == 0 ) opts.format = SEGY_SIGNED_CHAR_1_BYTE; if( opts.format == 0 ) { opts.errmsg = "invalid format argument. valid formats: " "ibm ieee short long char"; return opts; } break; case 'r': // intentional fallthrough case 't': if( opts.rsize == rallocsize ) { rallocsize *= 2; range* re = realloc( opts.r, rallocsize*sizeof( range ) ); if( !re ) { opts.errmsg = "Unable to reallocate memory"; return opts; } opts.r = re; } range* r = opts.r + opts.rsize; r->start = r->stop = r->step = 0; if( c == 't' ) { ret = parseint( optarg, &r->start ); if( ret ) { opts.errmsg = parsenum_errmsg[ ret ]; return opts; } if( r->start == 0 ) exit( errmsg( -3, "out of range" ) ); r->stop = r->start; goto done; } ret = sscanf(optarg," %d %d %d", &r->start, &r->stop, &r->step ); if( ret && ( r->start < 0 || r->stop < 0 || r->step < 0 ) ) { opts.errmsg = "range parameters must be positive"; return opts; } if( r->start == 0 ) exit( errmsg( -3, "out of range" ) ); // if sscanf found something it consumes 1 argument, and we // won't have to rewind optind if( !ret ) optind--; for( int pos = ret; optind < argc && pos < 3; pos++, optind++ ) { int val; ret = parseint( argv[ optind ], &val ); /* parseint returns 1 when the string contains more than an * int (or not an int at all) we assume that the remaining * range parameters were defaulted and give control back to * argument parsing * * such invocations include: * segyio-catr -r 1 foo.sgy * segyio-catr -r 1 2 -s foo.sgy */ if( ret == 0 ) *r = fill_range( *r, pos, val ); if( ret == 1 ) goto done; if( ret == 2 ) { opts.errmsg = parsenum_errmsg[ ret ]; return opts; } } done: ++opts.rsize; break; default: opts.help = 1; opts.errmsg = ""; return opts; } } if( argc - optind != 1 ) { errmsg( 0, "Wrong number of files" ); opts.errmsg = ""; return opts; } opts.src = argv[ optind ]; if( opts.rsize == 0 ) opts.rsize = 1; return opts; } int main( int argc, char** argv ) { struct options opts = parse_options( argc, argv ); if( opts.help ) exit( help() ); if( opts.version ) exit( printversion( "segyio-catr" ) ); if( opts.errmsg ) exit( errmsg( EINVAL, opts.errmsg ) ); int strict = opts.strict; const char** labels; switch( opts.labels ) { case su_labels: labels = su; break; case segyio_labels: labels = segynames; break; default: labels = su; break; } /* verify all ranges are sane */ for( range* r = opts.r; r < opts.r + opts.rsize; ++r ) { if( r->stop == 0 && r->step == 0 ) continue; if( r->start > r->stop && strict ) exit( errmsg( -3, "Range is empty" ) ); } char trheader[ TRHSIZE ]; char binheader[ BINSIZE ]; segy_file* src = segy_open( opts.src, "r" ); if( !src ) exit( errmsg2( errno, "Unable to open src", strerror( errno ) ) ); int err = segy_binheader( src, binheader ); if( err ) exit( errmsg( errno, "Unable to read binheader" ) ); int samnr = segy_samples( binheader ); int format = opts.format ? opts.format : segy_format( binheader ); switch( format ) { /* all good */ case SEGY_IBM_FLOAT_4_BYTE: case SEGY_SIGNED_INTEGER_4_BYTE: case SEGY_SIGNED_SHORT_2_BYTE: case SEGY_FIXED_POINT_WITH_GAIN_4_BYTE: case SEGY_IEEE_FLOAT_4_BYTE: case SEGY_SIGNED_CHAR_1_BYTE: break; /* * assume this header field is just not set, silently fall back * to 4-byte floats */ case 0: format = SEGY_IBM_FLOAT_4_BYTE; break; case SEGY_NOT_IN_USE_1: case SEGY_NOT_IN_USE_2: default: errmsg( 1, "sample format field is garbage. " "falling back to 4-byte float. " "override with --format" ); format = SEGY_IBM_FLOAT_4_BYTE; } int trace_bsize = segy_trsize( format, samnr ); long trace0 = segy_trace0( binheader ); int numtrh; err = segy_traces( src, &numtrh, trace0, trace_bsize ); if( err ) exit( errmsg( errno, "Unable to determine number of traces in file" ) ); /* * If any range field is defaulted (= 0), expand the defaults into sane * ranges */ for( range* r = opts.r; r < opts.r + opts.rsize; ++r ) { if( r->start == 0 ) r->start = 1; if( r->stop == 0 ) r->stop = r->start; if( r->step == 0 ) r->step = 1; } for( range* r = opts.r; r < opts.r + opts.rsize; ++r ) { for( int i = r->start; i <= r->stop; i += r->step ) { if( i > numtrh && strict ) exit( errmsg2( errno, "Unable to read traceheader", "out of range" ) ); if( i > numtrh ) break; err = segy_traceheader( src, i - 1, trheader, trace0, trace_bsize ); if( err ) exit( errmsg( errno, "Unable to read trace header" ) ); for( int j = 0; j < 91; j++ ) { int f; segy_get_field( trheader, fields[j], &f ); if( opts.nonzero && !f ) continue; if( opts.description ) { printf( "%s\t%d\t%d\t%s\n", labels[j], f, fields[ j ], desc[ j ] ); } else printf( "%s\t%d\n", labels[j], f ); } } } free( opts.r ); segy_close( src ); return 0; } segyio-1.8.3/applications/segyio-catb.c0000664000372000037200000001606413407674361017506 0ustar travistravis#include #include #include #include #include #include #include "apputils.h" #include static int printhelp(){ puts( "Usage: segyio-catb [OPTION]... [FILE]...\n" "Concatenate the binary header from FILE(s) to seismic unix " "output.\n" "\n" "-n, --nonzero only print fields with non-zero values\n" "-d, --description print with byte offset and field description\n" " --version output version information and exit\n" " --help display this help and exit\n" "\n" ); return 0; } static int get_binary_value( char* binheader, int bfield ){ int32_t f; segy_get_bfield( binheader, bfield, &f ); return f; } struct options { int version; int help; int nonzero; int description; const char* errmsg; }; static struct options parse_options( int argc, char** argv ){ struct options opts; opts.nonzero = 0; opts.description = 0; opts.version = 0, opts.help = 0; opts.errmsg = NULL; static struct option long_options[] = { {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"description", no_argument, 0, 'd'}, {"nonzero", no_argument, 0, 'n'}, {0, 0, 0, 0} }; opterr = 1; while( true ){ int option_index = 0; int c = getopt_long( argc, argv, "nd", long_options, &option_index); if ( c == -1 ) break; switch( c ){ case 0: break; case 'h': opts.help = 1; return opts; case 'V': opts.version = 1; return opts; case 'd': opts.description = 1; break; case 'n': opts.nonzero = 1; break; default: opts.help = 1; opts.errmsg = ""; return opts; } } return opts; } int main( int argc, char** argv ){ static const char* su[ 30 ] = { "jobid", "lino", "reno", "ntrpr", "nart", "hdt", "dto", "hns", "nso", "format", "fold", "tsort", "vscode", "hsfs", "hsfe", "hslen", "hstyp", "schn", "hstas", "hstae", "htatyp", "hcorr", "bgrcv", "rcvm", "mfeet", "polyt", "vpol", "rev", "trflag", "exth" }; static const char* su_desc[ 30 ] = { "Job identification number" , "Line number" , "Reel number" , "Number of data traces per ensemble" , "Number of auxiliary traces per ensemble" , "Sample interval in microseconds (μs)" , "Sample interval in microseconds (μs) of original field recording" , "Number of samples per data trace" , "Number of samples per data trace for original field recording" , "Data sample format code" , "Ensemble fold" , "Trace sorting code" , "Vertical sum code" , "Sweep frequency at start (Hz)" , "Sweep frequency at end (Hz)" , "Sweep length (ms)" , "Sweep type code" , "Trace number of sweep channel" , "Sweep trace taper length in milliseconds at start if tapered" , "Sweep trace taper length in milliseconds at end" , "Taper type" , "Correlated data traces" , "Binary gain recovered" , "Amplitude recovery method" , "Measurement system" , "Impulse signal polarity" , "Vibratory polarity code" , "SEG Y Format Revision Number" , "Fixed length trace flag" , "Number of 3200-byte, Extended Textual File Headers" }; static int bfield_value[ 30 ] = { SEGY_BIN_JOB_ID, SEGY_BIN_LINE_NUMBER, SEGY_BIN_REEL_NUMBER, SEGY_BIN_TRACES, SEGY_BIN_AUX_TRACES, SEGY_BIN_INTERVAL, SEGY_BIN_INTERVAL_ORIG, SEGY_BIN_SAMPLES, SEGY_BIN_SAMPLES_ORIG, SEGY_BIN_FORMAT, SEGY_BIN_ENSEMBLE_FOLD, SEGY_BIN_SORTING_CODE, SEGY_BIN_VERTICAL_SUM, SEGY_BIN_SWEEP_FREQ_START, SEGY_BIN_SWEEP_FREQ_END, SEGY_BIN_SWEEP_LENGTH, SEGY_BIN_SWEEP, SEGY_BIN_SWEEP_CHANNEL, SEGY_BIN_SWEEP_TAPER_START, SEGY_BIN_SWEEP_TAPER_END, SEGY_BIN_TAPER, SEGY_BIN_CORRELATED_TRACES, SEGY_BIN_BIN_GAIN_RECOVERY, SEGY_BIN_AMPLITUDE_RECOVERY, SEGY_BIN_MEASUREMENT_SYSTEM, SEGY_BIN_IMPULSE_POLARITY, SEGY_BIN_VIBRATORY_POLARITY, SEGY_BIN_SEGY_REVISION, SEGY_BIN_TRACE_FLAG, SEGY_BIN_EXT_HEADERS }; if( argc == 1 ){ int err = errmsg(2, "Missing argument\n"); printhelp(); return err; } struct options opts = parse_options( argc, argv ); if( opts.help ) return printhelp(); if( opts.version ) return printversion( "segyio-catb" ); for( int i = optind; i < argc; ++i ){ segy_file* fp = segy_open( argv[ i ], "r" ); if( !fp ) return errmsg(opterr, "No such file or directory"); char binheader[ SEGY_BINARY_HEADER_SIZE ]; int err = segy_binheader( fp, binheader ); if( err ) return errmsg(opterr, "Unable to read binary header"); for( int c = 0; c < 30; ++c ){ int field = get_binary_value( binheader, bfield_value[ c ] ); if( opts.nonzero && !field) continue; if( opts.description ) { int byte_offset = (bfield_value[ c ] - SEGY_TEXT_HEADER_SIZE); printf( "%s\t%d\t%d\t%s\n", su[ c ], field, byte_offset, su_desc[ c ] ); } else printf( "%s\t%d\n", su[ c ], field ); } segy_close( fp ); } return 0; } segyio-1.8.3/applications/segyinspect.c0000664000372000037200000001240713407674361017632 0ustar travistravis#include #include #include #include #include #include static const char* getSampleFormatName( int format ) { switch( format ) { case SEGY_IBM_FLOAT_4_BYTE: return "IBM Float"; case SEGY_SIGNED_INTEGER_4_BYTE: return "Int 32"; case SEGY_SIGNED_SHORT_2_BYTE: return "Int 16"; case SEGY_FIXED_POINT_WITH_GAIN_4_BYTE: return "Fixed Point with gain (Obsolete)"; case SEGY_IEEE_FLOAT_4_BYTE: return "IEEE Float"; case SEGY_NOT_IN_USE_1: return "Not in Use 1"; case SEGY_NOT_IN_USE_2: return "Not in Use 2"; case SEGY_SIGNED_CHAR_1_BYTE: return "Int 8"; default: return "Unknown"; } } static const char* getFastestDirectionName( int sorting ) { if ( sorting == SEGY_CROSSLINE_SORTING) { return "CROSSLINE"; } else { return "INLINE_SORTING"; } } int main(int argc, char* argv[]) { int err; if( argc < 2 ) { puts("Missing argument, expected run signature:"); printf(" %s [mmap] [INLINE_BYTE CROSSLINE_BYTE]\n", argv[0]); printf(" Inline and crossline bytes default to: 189 and 193\n"); exit(1); } int xl_field = SEGY_TR_CROSSLINE; int il_field = SEGY_TR_INLINE; bool memory_map = argc > 2 && strcmp( argv[ 2 ], "mmap" ) == 0; if( ( memory_map && argc > 4 ) || ( !memory_map && argc > 2 ) ) { int argindex = memory_map ? 2 : 3; il_field = atoi(argv[ argindex + 0 ]); xl_field = atoi(argv[ argindex + 1 ]); } clock_t start = clock(); segy_file* fp = segy_open( argv[ 1 ], "rb" ); if( !fp ) { perror( "fopen()" ); exit( SEGY_FOPEN_ERROR ); } if( memory_map ) { err = segy_mmap( fp ); if( err != SEGY_OK ) fputs( "Could not mmap file. Using fstream fallback.", stderr ); } char header[ SEGY_BINARY_HEADER_SIZE ]; err = segy_binheader( fp, header ); if( err != 0 ) { perror( "Unable to read segy binary header" ); exit( err ); } const int format = segy_format( header ); const int samples = segy_samples( header ); const long trace0 = segy_trace0( header ); const int trace_bsize = segy_trace_bsize( samples ); int traces; err = segy_traces( fp, &traces, trace0, trace_bsize ); if( err != 0 ) { perror( "Could not determine traces" ); exit( err ); } int sorting; err = segy_sorting( fp, il_field, xl_field, SEGY_TR_OFFSET, &sorting, trace0, trace_bsize ); if( err != 0 ) { perror( "Could not determine sorting" ); exit( err ); } int offsets; err = segy_offsets( fp, il_field, xl_field, traces, &offsets, trace0, trace_bsize ); if( err != 0 ) { perror( "Could not determine offsets" ); exit( err ); } int inline_count, crossline_count; if( sorting == SEGY_INLINE_SORTING ) { err = segy_count_lines( fp, xl_field, offsets, &inline_count, &crossline_count, trace0, trace_bsize ); } else { err = segy_count_lines( fp, il_field, offsets, &crossline_count, &inline_count, trace0, trace_bsize ); } if( err != 0 ) { fprintf( stderr, "Errcode %d\n", err ); perror( "Could not count lines" ); exit( err ); } int* inline_indices = malloc( sizeof( int ) * inline_count ); int* crossline_indices = malloc( sizeof( int ) * crossline_count ); err = segy_inline_indices( fp, il_field, sorting, inline_count, crossline_count, offsets, inline_indices, trace0, trace_bsize ); if( err != 0 ) { perror( "Could not determine inline numbers" ); exit( err ); } err = segy_crossline_indices( fp, xl_field, sorting, inline_count, crossline_count, offsets, crossline_indices, trace0, trace_bsize ); if( err != 0 ) { fprintf( stderr, "Errcode %d\n", err ); perror( "Could not determine crossline numbers" ); exit( err ); } clock_t diff = clock() - start; printf( "Crosslines..........: %d\n", crossline_count); printf( "Inlines.............: %d\n", inline_count); printf( "Offsets.............: %d\n", offsets); printf( "Samples.............: %d\n", samples); printf( "Sample format.......: %s\n", getSampleFormatName( format ) ); printf( "Fastest direction...: %s\n", getFastestDirectionName( sorting ) ); puts(""); puts("Crossline indexes:"); for( int i = 0; i < crossline_count; i++ ) { printf( "%d ", crossline_indices[i] ); } puts("\n"); puts("Inline indexes:"); for( int i = 0; i < inline_count; i++ ) { printf( "%d ", inline_indices[i] ); } puts("\n"); puts("Sample indexes:"); //for (int i = 0; i < spec->sample_count; i++) { // printf("%.2f ", spec->sample_indexes[i]); //} puts("\n"); printf("Inspection took : %.2f s\n", (double) diff / CLOCKS_PER_SEC); free( inline_indices ); free( crossline_indices ); segy_close( fp ); exit(0); } segyio-1.8.3/applications/CMakeLists.txt0000664000372000037200000001217313407674361017671 0ustar travistravisproject(segyio-apps) if (NOT BUILD_BIN) return () endif () if( NOT HAVE_GETOPT_H OR NOT HAVE_GETOPT_LONG ) message(WARNING "Could not find getopt. Not building applications.") return () endif () add_library(apputils STATIC apputils.c) target_link_libraries(apputils segyio) target_compile_options(apputils BEFORE PRIVATE $<$:${warnings-c}> ${c99} ) target_compile_definitions(apputils PUBLIC -Dsegyio_MAJOR=${segyio_MAJOR} -Dsegyio_MINOR=${segyio_MINOR} ) add_executable(segyinfo segyinfo.c) target_link_libraries(segyinfo segyio) target_compile_options(segyinfo BEFORE PRIVATE $<$:${warnings-c}> ${c99} ) add_executable(segyinspect segyinspect.c) target_link_libraries(segyinspect segyio) target_compile_options(segyinspect BEFORE PRIVATE $<$:${warnings-c}> ${c99} ) add_executable(segyio-cath segyio-cath.c) target_link_libraries(segyio-cath segyio apputils) target_compile_options(segyio-cath BEFORE PRIVATE $<$:${warnings-c}> ${c99} ) add_executable(segyio-catb segyio-catb.c) target_link_libraries(segyio-catb segyio apputils) target_compile_options(segyio-catb BEFORE PRIVATE $<$:${warnings-c}> ${c99} ) add_executable(segyio-catr segyio-catr.c) target_link_libraries(segyio-catr segyio apputils) target_compile_options(segyio-catr BEFORE PRIVATE $<$:${warnings-c}> ${c99} ) add_executable(segyio-crop segyio-crop.c) target_link_libraries(segyio-crop segyio apputils) target_compile_options(segyio-crop BEFORE PRIVATE $<$:${warnings-c}> ${c99} ) add_executable(flip-endianness flip-endianness.cpp) target_link_libraries(flip-endianness segyio) target_compile_options(flip-endianness BEFORE PRIVATE $<$:${warnings-c}> ${c++11} ) install(TARGETS segyio-cath segyio-catb segyio-catr segyio-crop DESTINATION ${CMAKE_INSTALL_BINDIR}) if (NOT BUILD_TESTING) return () endif () set(small ${testdata}/small.sgy) set(test ${CMAKE_CURRENT_SOURCE_DIR}/test) add_test(NAME catr.arg.t1 COMMAND segyio-catr -t 0 ${small}) add_test(NAME catr.arg.t2 COMMAND segyio-catr -t 5 ${small}) add_test(NAME catr.arg.r1 COMMAND segyio-catr -r 5 ${small}) add_test(NAME catr.arg.r2 COMMAND segyio-catr -r 1 2 ${small}) add_test(NAME catr.arg.r3 COMMAND segyio-catr -r 1 2 3 ${small} -r 5 6) add_test(NAME catr.arg.multiple COMMAND segyio-catr "-r 1" 5 2 ${small} -r 1 6) add_test(NAME catr.arg.rt COMMAND segyio-catr -r 1 2 ${small} -t 5) add_test(NAME catr.arg.fmt COMMAND segyio-catr -f ieee ${small}) add_test(NAME catb.arg.help COMMAND segyio-catb --help) add_test(NAME catb.fail.nosegy COMMAND segyio-catb ${test}/catb.output) add_test(NAME catb.fail.nofile COMMAND segyio-catb not-exist) add_test(NAME catb.fail.noarg COMMAND segyio-catb) add_test(NAME cath.arg.help COMMAND segyio-cath --help) add_test(NAME cath.fail.nosegy COMMAND segyio-cath ${test}/cath.output) add_test(NAME cath.fail.nofile COMMAND segyio-cath --strict not-exist) add_test(NAME cath.fail.noarg COMMAND segyio-cath) set_tests_properties(catr.arg.t1 catb.fail.nosegy catb.fail.nofile catb.fail.noarg cath.fail.nosegy cath.fail.nofile cath.fail.noarg PROPERTIES WILL_FAIL ON) add_custom_target(test-app-output ALL DEPENDS catb.out cath.out catr.out crop-ns.out crop-ns.sgy ) add_custom_command( OUTPUT catb.out cath.out catr.out COMMENT "running applications for output comparison" DEPENDS segyio-catb segyio-cath segyio-catr test/catb.output test/cath.output test/catr.output COMMAND segyio-catb ${small} > catb.out COMMAND segyio-catb ${small} -n -d > catbnd.out COMMAND segyio-cath ${small} > cath.out COMMAND segyio-catr -r 4 9 -t 12 ${small} > catr.out COMMAND segyio-catr -t 1 ${small} -n -d > catrnd.out ) add_custom_command( OUTPUT crop-ns.out crop-ns.sgy COMMENT "running applications for crop testing" DEPENDS segyio-crop segyio-catr test/crop-ns.output COMMAND segyio-crop -S 25 ${small} crop-ns.sgy COMMAND segyio-catr crop-ns.sgy > crop-ns.out ) add_test(NAME catb.output COMMAND ${CMAKE_COMMAND} -E compare_files ${test}/catb.output catb.out ) add_test(NAME catb.output.nd COMMAND ${CMAKE_COMMAND} -E compare_files ${test}/catbnd.output catbnd.out ) add_test(NAME cath.output COMMAND ${CMAKE_COMMAND} -E compare_files ${test}/cath.output cath.out ) add_test(NAME catr.output COMMAND ${CMAKE_COMMAND} -E compare_files ${test}/catr.output catr.out ) add_test(NAME catr.output.nd COMMAND ${CMAKE_COMMAND} -E compare_files ${test}/catrnd.output catrnd.out ) add_test(NAME crop.samplecount COMMAND ${CMAKE_COMMAND} -E compare_files ${test}/crop-ns.output crop-ns.out ) segyio-1.8.3/applications/test/0000775000372000037200000000000013407674361016104 5ustar travistravissegyio-1.8.3/applications/test/catb.output0000664000372000037200000000034513407674361020301 0ustar travistravisjobid 0 lino 0 reno 0 ntrpr 25 nart 0 hdt 4000 dto 0 hns 50 nso 0 format 1 fold 0 tsort 0 vscode 0 hsfs 0 hsfe 0 hslen 0 hstyp 0 schn 0 hstas 0 hstae 0 htatyp 0 hcorr 0 bgrcv 0 rcvm 0 mfeet 0 polyt 0 vpol 0 rev 0 trflag 0 exth 0 segyio-1.8.3/applications/test/catr.output0000664000372000037200000001104113407674361020314 0ustar travistravistracl 0 tracr 0 fldr 0 tracf 0 ep 0 cdp 0 cdpt 0 trid 0 nvs 0 nhs 0 duse 0 offset 1 gelev 0 selev 0 sdepth 0 gdel 0 sdel 0 swdep 0 gwdep 0 scalel 0 scalco 0 sx 0 sy 0 gx 0 gy 0 counit 0 wevel 0 swevel 0 sut 0 gut 0 sstat 0 gstat 0 tstat 0 laga 0 lagb 0 delrt 0 muts 0 mute 0 ns 0 dt 0 gain 0 igc 0 igi 0 corr 0 sfs 0 sfe 0 slen 0 styp 0 stat 0 stae 0 tatyp 0 afilf 0 afils 0 nofilf 0 nofils 0 lcf 0 hcf 0 lcs 0 hcs 0 year 0 day 0 hour 0 minute 0 sec 0 timbas 0 trwf 0 grnors 0 grnofr 0 grnlof 0 gaps 0 otrav 0 cdpx 0 cdpy 0 iline 1 xline 23 sp 0 scalsp 0 trunit 0 tdcm 0 tdcp 0 tdunit 0 triden 0 sctrh 0 stype 0 sedm 0 sede 0 smm 0 sme 0 smunit 0 uint1 0 uint2 0 tracl 0 tracr 0 fldr 0 tracf 0 ep 0 cdp 0 cdpt 0 trid 0 nvs 0 nhs 0 duse 0 offset 1 gelev 0 selev 0 sdepth 0 gdel 0 sdel 0 swdep 0 gwdep 0 scalel 0 scalco 0 sx 0 sy 0 gx 0 gy 0 counit 0 wevel 0 swevel 0 sut 0 gut 0 sstat 0 gstat 0 tstat 0 laga 0 lagb 0 delrt 0 muts 0 mute 0 ns 0 dt 0 gain 0 igc 0 igi 0 corr 0 sfs 0 sfe 0 slen 0 styp 0 stat 0 stae 0 tatyp 0 afilf 0 afils 0 nofilf 0 nofils 0 lcf 0 hcf 0 lcs 0 hcs 0 year 0 day 0 hour 0 minute 0 sec 0 timbas 0 trwf 0 grnors 0 grnofr 0 grnlof 0 gaps 0 otrav 0 cdpx 0 cdpy 0 iline 1 xline 24 sp 0 scalsp 0 trunit 0 tdcm 0 tdcp 0 tdunit 0 triden 0 sctrh 0 stype 0 sedm 0 sede 0 smm 0 sme 0 smunit 0 uint1 0 uint2 0 tracl 0 tracr 0 fldr 0 tracf 0 ep 0 cdp 0 cdpt 0 trid 0 nvs 0 nhs 0 duse 0 offset 1 gelev 0 selev 0 sdepth 0 gdel 0 sdel 0 swdep 0 gwdep 0 scalel 0 scalco 0 sx 0 sy 0 gx 0 gy 0 counit 0 wevel 0 swevel 0 sut 0 gut 0 sstat 0 gstat 0 tstat 0 laga 0 lagb 0 delrt 0 muts 0 mute 0 ns 0 dt 0 gain 0 igc 0 igi 0 corr 0 sfs 0 sfe 0 slen 0 styp 0 stat 0 stae 0 tatyp 0 afilf 0 afils 0 nofilf 0 nofils 0 lcf 0 hcf 0 lcs 0 hcs 0 year 0 day 0 hour 0 minute 0 sec 0 timbas 0 trwf 0 grnors 0 grnofr 0 grnlof 0 gaps 0 otrav 0 cdpx 0 cdpy 0 iline 2 xline 20 sp 0 scalsp 0 trunit 0 tdcm 0 tdcp 0 tdunit 0 triden 0 sctrh 0 stype 0 sedm 0 sede 0 smm 0 sme 0 smunit 0 uint1 0 uint2 0 tracl 0 tracr 0 fldr 0 tracf 0 ep 0 cdp 0 cdpt 0 trid 0 nvs 0 nhs 0 duse 0 offset 1 gelev 0 selev 0 sdepth 0 gdel 0 sdel 0 swdep 0 gwdep 0 scalel 0 scalco 0 sx 0 sy 0 gx 0 gy 0 counit 0 wevel 0 swevel 0 sut 0 gut 0 sstat 0 gstat 0 tstat 0 laga 0 lagb 0 delrt 0 muts 0 mute 0 ns 0 dt 0 gain 0 igc 0 igi 0 corr 0 sfs 0 sfe 0 slen 0 styp 0 stat 0 stae 0 tatyp 0 afilf 0 afils 0 nofilf 0 nofils 0 lcf 0 hcf 0 lcs 0 hcs 0 year 0 day 0 hour 0 minute 0 sec 0 timbas 0 trwf 0 grnors 0 grnofr 0 grnlof 0 gaps 0 otrav 0 cdpx 0 cdpy 0 iline 2 xline 21 sp 0 scalsp 0 trunit 0 tdcm 0 tdcp 0 tdunit 0 triden 0 sctrh 0 stype 0 sedm 0 sede 0 smm 0 sme 0 smunit 0 uint1 0 uint2 0 tracl 0 tracr 0 fldr 0 tracf 0 ep 0 cdp 0 cdpt 0 trid 0 nvs 0 nhs 0 duse 0 offset 1 gelev 0 selev 0 sdepth 0 gdel 0 sdel 0 swdep 0 gwdep 0 scalel 0 scalco 0 sx 0 sy 0 gx 0 gy 0 counit 0 wevel 0 swevel 0 sut 0 gut 0 sstat 0 gstat 0 tstat 0 laga 0 lagb 0 delrt 0 muts 0 mute 0 ns 0 dt 0 gain 0 igc 0 igi 0 corr 0 sfs 0 sfe 0 slen 0 styp 0 stat 0 stae 0 tatyp 0 afilf 0 afils 0 nofilf 0 nofils 0 lcf 0 hcf 0 lcs 0 hcs 0 year 0 day 0 hour 0 minute 0 sec 0 timbas 0 trwf 0 grnors 0 grnofr 0 grnlof 0 gaps 0 otrav 0 cdpx 0 cdpy 0 iline 2 xline 22 sp 0 scalsp 0 trunit 0 tdcm 0 tdcp 0 tdunit 0 triden 0 sctrh 0 stype 0 sedm 0 sede 0 smm 0 sme 0 smunit 0 uint1 0 uint2 0 tracl 0 tracr 0 fldr 0 tracf 0 ep 0 cdp 0 cdpt 0 trid 0 nvs 0 nhs 0 duse 0 offset 1 gelev 0 selev 0 sdepth 0 gdel 0 sdel 0 swdep 0 gwdep 0 scalel 0 scalco 0 sx 0 sy 0 gx 0 gy 0 counit 0 wevel 0 swevel 0 sut 0 gut 0 sstat 0 gstat 0 tstat 0 laga 0 lagb 0 delrt 0 muts 0 mute 0 ns 0 dt 0 gain 0 igc 0 igi 0 corr 0 sfs 0 sfe 0 slen 0 styp 0 stat 0 stae 0 tatyp 0 afilf 0 afils 0 nofilf 0 nofils 0 lcf 0 hcf 0 lcs 0 hcs 0 year 0 day 0 hour 0 minute 0 sec 0 timbas 0 trwf 0 grnors 0 grnofr 0 grnlof 0 gaps 0 otrav 0 cdpx 0 cdpy 0 iline 2 xline 23 sp 0 scalsp 0 trunit 0 tdcm 0 tdcp 0 tdunit 0 triden 0 sctrh 0 stype 0 sedm 0 sede 0 smm 0 sme 0 smunit 0 uint1 0 uint2 0 tracl 0 tracr 0 fldr 0 tracf 0 ep 0 cdp 0 cdpt 0 trid 0 nvs 0 nhs 0 duse 0 offset 1 gelev 0 selev 0 sdepth 0 gdel 0 sdel 0 swdep 0 gwdep 0 scalel 0 scalco 0 sx 0 sy 0 gx 0 gy 0 counit 0 wevel 0 swevel 0 sut 0 gut 0 sstat 0 gstat 0 tstat 0 laga 0 lagb 0 delrt 0 muts 0 mute 0 ns 0 dt 0 gain 0 igc 0 igi 0 corr 0 sfs 0 sfe 0 slen 0 styp 0 stat 0 stae 0 tatyp 0 afilf 0 afils 0 nofilf 0 nofils 0 lcf 0 hcf 0 lcs 0 hcs 0 year 0 day 0 hour 0 minute 0 sec 0 timbas 0 trwf 0 grnors 0 grnofr 0 grnlof 0 gaps 0 otrav 0 cdpx 0 cdpy 0 iline 3 xline 21 sp 0 scalsp 0 trunit 0 tdcm 0 tdcp 0 tdunit 0 triden 0 sctrh 0 stype 0 sedm 0 sede 0 smm 0 sme 0 smunit 0 uint1 0 uint2 0 segyio-1.8.3/applications/test/catrnd.output0000664000372000037200000000022113407674361020634 0ustar travistravisoffset 1 37 Distance from center of the source point to the center of the receiver group iline 1 189 Inline number xline 20 193 Crossline number segyio-1.8.3/applications/test/cath.output0000664000372000037200000000625013407674361020310 0ustar travistravisC 1 DATE: 2016-09-19 C 2 AN INCREASE IN AMPLITUDE EQUALS AN INCREASE IN ACOUSTIC IMPEDANCE C 3 Written by libsegyio (python) C 4 C 5 C 6 C 7 C 8 C 9 C10 C11 TRACE HEADER POSITION: C12 INLINE BYTES 189-193 | OFFSET BYTES 037-041 C13 CROSSLINE BYTES 193-197 | C14 C15 END EBCDIC HEADER C16 C17 C18 C19 C20 C21 C22 C23 C24 C25 C26 C27 C28 C29 C30 C31 C32 C33 C34 C35 C36 C37 C38 C39 C40 segyio-1.8.3/applications/test/crop-ns.output0000664000372000037200000000122713407674361020751 0ustar travistravistracl 0 tracr 0 fldr 0 tracf 0 ep 0 cdp 0 cdpt 0 trid 0 nvs 0 nhs 0 duse 0 offset 1 gelev 0 selev 0 sdepth 0 gdel 0 sdel 0 swdep 0 gwdep 0 scalel 0 scalco 0 sx 0 sy 0 gx 0 gy 0 counit 0 wevel 0 swevel 0 sut 0 gut 0 sstat 0 gstat 0 tstat 0 laga 0 lagb 0 delrt 0 muts 0 mute 0 ns 8 dt 0 gain 0 igc 0 igi 0 corr 0 sfs 0 sfe 0 slen 0 styp 0 stat 0 stae 0 tatyp 0 afilf 0 afils 0 nofilf 0 nofils 0 lcf 0 hcf 0 lcs 0 hcs 0 year 0 day 0 hour 0 minute 0 sec 0 timbas 0 trwf 0 grnors 0 grnofr 0 grnlof 0 gaps 0 otrav 0 cdpx 0 cdpy 0 iline 1 xline 20 sp 0 scalsp 0 trunit 0 tdcm 0 tdcp 0 tdunit 0 triden 0 sctrh 0 stype 0 sedm 0 sede 0 smm 0 sme 0 smunit 0 uint1 0 uint2 0 segyio-1.8.3/applications/test/catbnd.output0000664000372000037200000000026013407674361020617 0ustar travistravisntrpr 25 13 Number of data traces per ensemble hdt 4000 17 Sample interval in microseconds (μs) hns 50 21 Number of samples per data trace format 1 25 Data sample format code segyio-1.8.3/applications/segyio-cath.c0000664000372000037200000001206013407674361017504 0ustar travistravis#include #include #include #include #include #include #include "apputils.c" #include static int help() { puts( "Usage: segyio-cath [OPTION]... [FILE]...\n" "Concatenate the textual header(s) from FILE(s) to standard output.\n" "\n" "-n, --num the textual header to show, starts at 0\n" "-a, --all all textual headers\n" "-s, --strict abort if a header or file is not found\n" " primarily meant for shell scripts\n" "-S, --nonstrict ignore missing headers\n" " this is the default behaviour\n" " --version output version information and exit\n" " --help display this help and exit\n" "\n" "By default, only the non-extended header is printed, which is\n" "equivalent to --num 0\n" ); return 0; } static int ext_headers( segy_file* fp ) { char binary[ SEGY_BINARY_HEADER_SIZE ]; int err = segy_binheader( fp, binary ); if( err ) return -1; int32_t ext; err = segy_get_bfield( binary, SEGY_BIN_EXT_HEADERS, &ext ); if( err ) return -2; return ext; } static void print_header( const char* header ) { for( int line = 0, ch = 0; line < 40; ++line ) { for( int c = 0; c < 80; ++c, ++ch ) putchar( header[ ch ] ); putchar( '\n' ); } } int main( int argc, char** argv ) { static int all = false; static int strict = false; static int version = 0; static struct option long_options[] = { { "num", required_argument, 0, 'n' }, { "all", no_argument, &all, 1 }, { "strict", no_argument, &strict, 1 }, { "nonstrict", no_argument, &strict, 0 }, { "version", no_argument, &version, 1 }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; int num_alloc_sz = 32; int* num = calloc( sizeof( int ), num_alloc_sz ); int num_sz = 0; while( true ) { int option_index = 0; int c = getopt_long( argc, argv, "n:asS", long_options, &option_index ); if( c == -1 ) break; char* endptr; switch( c ) { case 0: break; case 'h': exit( help() ); case 's': strict = 1; break; case 'S': strict = 0; break; case 'a': all = 1; break; case 'n': if( version ) break; if( num_sz == num_alloc_sz - 1 ) { num_alloc_sz *= 2; int* re = realloc( num, num_alloc_sz * sizeof( int ) ); if( !re ) exit( errmsg( errno, "Unable to alloc" ) ); num = re; } num[ num_sz ] = strtol( optarg, &endptr, 10 ); if( *endptr != '\0' ) exit( errmsg( EINVAL, "num must be an integer" ) ); if( num[ num_sz ] < 0 ) exit( errmsg( EINVAL, "num must be non-negative" ) ); break; default: exit( help() ); } } if( version ) exit( printversion( "segyio-cath" ) ); char header[ SEGY_TEXT_HEADER_SIZE + 1 ] = { 0 }; if( argc - optind < 1 ) exit( errmsg( 2, "missing file operand\n" "Try 'segyio-cath --help' for more information." ) ); for( int i = optind; i < argc; ++i ) { segy_file* fp = segy_open( argv[ i ], "r" ); if( !fp ) fprintf( stderr, "segyio-cath: %s: No such file or directory\n", argv[ i ] ); if( !fp && strict ) exit( errmsg( 2, NULL ) ); if( !fp ) continue; if( num_sz == 0 ) num_sz = 1; const int exts = ext_headers( fp ); if( exts < 0 ) exit( errmsg( 1, "Unable to read binary header" ) ); if( all ) { /* just create the list 0,1,2... as if it was passed explicitly */ if( exts >= num_alloc_sz ) { num_alloc_sz = exts * 2; int* re = realloc( num, num_alloc_sz * sizeof( int ) ); if( !re ) exit( errmsg( errno, "Unable to alloc" ) ); num = re; } num_sz = exts + 1; num[ 0 ] = 0; for( int j = 0; j < exts; ++j ) num[ j + 1 ] = j; } for( int j = 0; j < num_sz; ++j ) { if( strict && ( num[ j ] < 0 || num[ j ] > exts ) ) exit( errmsg( EINVAL, "Header index out of range" ) ); if( num[ j ] < 0 || num[ j ] > exts ) continue; int err = num[ j ] == 0 ? segy_read_textheader( fp, header ) : segy_read_ext_textheader( fp, num[ j ] - 1, header ); if( err != 0 ) exit( errmsg( errno, "Unable to read header" ) ); print_header( header ); } segy_close( fp ); } free( num ); return 0; } segyio-1.8.3/applications/apputils.c0000664000372000037200000000227413407674361017137 0ustar travistravis#include #include #include #include "apputils.h" #include int errmsg( int errcode, const char* msg ) { if( !msg ) return errcode; fflush( stdout ); fputs( msg, stderr ); fputc( '\n', stderr ); fflush( stderr ); return errcode; } int errmsg2( int errcode, const char* prelude, const char* msg ) { if( !prelude ) return errmsg( errcode, msg ); fflush( stdout ); fputs( prelude, stderr ); fputc( ':', stderr ); fputc( ' ', stderr ); fflush( stderr ); return errmsg( errcode, msg ); } int parseint( const char* str, int* x ) { char* endptr; *x = strtol( str, &endptr, 10 ); if( *endptr != '\0' ) return 1; if( *x < 0 ) return 2; return 0; } int bfield( const char* header, int field ) { int32_t f; int err = segy_get_bfield( header, field, &f ); if( err ) return -1; return f; } int trfield( const char* header, int field ) { int32_t f; int err = segy_get_field( header, field, &f ); if( err ) return -1; return f; } int printversion( const char* name ) { printf( "%s (segyio version %d.%d)\n", name, segyio_MAJOR, segyio_MINOR ); return 0; } segyio-1.8.3/applications/flip-endianness.cpp0000664000372000037200000001574713407674361020726 0ustar travistravis#include #include #include #include #include #include #include #include #include namespace { static struct option long_options[] = { { "ext", required_argument, 0, 'e' }, { "samples", required_argument, 0, 's' }, { "samplesize", required_argument, 0, 'F' }, { "format", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; int help( int errc = EXIT_SUCCESS ) { auto& out = errc == EXIT_SUCCESS ? std::cout : std::cerr; out << "usage: flip-endianness [OPTS...] IN OUT\n\n" << "swap endianness of values. this program is only intended\n" << "for testing segyio, and is not supported.\n" << "This program does not flip values of unassigned header words\n" << "\n" << "options: \n" << "-e, --ext N external headers\n" << "-s, --samples N samples-per-trace\n" << "-F, --samplesize N sample size (default: 4)\n" << "-f, --format [id] sample size from format\n" << " formats: ibm ieee byte short int\n" << "--help this text\n" ; return errc; } int size_from_format( const std::string& fmt ) { if( fmt == "ibm" ) return 4; if( fmt == "ieee" ) return 4; if( fmt == "byte" ) return 1; if( fmt == "short" ) return 2; if( fmt == "int" ) return 4; std::cerr << "unknown format '" << fmt << "', expected one of: " << "ibm iee byte short int\n"; std::exit( EXIT_FAILURE ); } void flip_binary_header( char* xs ) { std::vector< int > sizes; sizes.insert( sizes.end(), 3, 4 ); sizes.insert( sizes.end(), 24, 2 ); for( auto size : sizes ) { std::reverse( xs, xs + size ); xs += size; } xs += 240; for( auto size : { 2, 2, 2 } ) { std::reverse( xs, xs + size ); xs += size; } } void flip_trace_header( char* xs ) { std::vector< int > sizes; sizes.insert( sizes.end(), 7, 4); sizes.insert( sizes.end(), 4, 2); sizes.insert( sizes.end(), 8, 4); sizes.insert( sizes.end(), 2, 2); sizes.insert( sizes.end(), 4, 4); sizes.insert( sizes.end(), 46, 2); sizes.insert( sizes.end(), 5, 4); sizes.insert( sizes.end(), 2, 2); sizes.insert( sizes.end(), 1, 4); sizes.insert( sizes.end(), 5, 2); sizes.insert( sizes.end(), 1, 4); sizes.insert( sizes.end(), 1, 2); sizes.insert( sizes.end(), 1, 4); sizes.insert( sizes.end(), 2, 2); for( auto size : sizes ) { std::reverse( xs, xs + size ); xs += size; } } void flip_trace_data( char* xs, int samples, int samplesize ) { for( int i = 0; i < samples; ++i ) { std::reverse( xs, xs + samplesize ); xs += samplesize; } } } int main( int argc, char** argv ) { int ext = 0; int samples = 0; int samplesize = 4; while( true ) { int option_index = 0; int c = getopt_long( argc, argv, "e:s:F:f:", long_options, &option_index ); if( c == -1 ) break; switch( c ) { case 0: break; case 'e': std::exit( help() ); case 't': ext = std::stoi( optarg ); break; case 's': samples = std::stoi( optarg ); break; case 'F': samplesize = std::stoi( optarg ); break; case 'f': samplesize = size_from_format( optarg ); break; default: break; } } if( argc - optind != 2 ) { std::exit( help( EXIT_FAILURE ) ); } if( std::strcmp( argv[ optind ], argv[ optind + 1 ] ) == 0 ) { std::cerr << "output file cannot be the same as input file\n"; std::exit( EXIT_FAILURE ); } auto* in = std::fopen( argv[ optind ], "rb" ); if( !in ) { std::perror( "unable to open input file" ); std::exit( EXIT_FAILURE ); } auto* out = std::fopen( argv[ optind + 1 ], "wb" ); if( !out ) { std::perror( "unable to open output file" ); std::exit( EXIT_FAILURE ); } const auto trsize = samples * samplesize; if( trsize <= 0 ) { std::cerr << "trace size must be non-negative (was " << trsize << ")\n"; std::exit( EXIT_FAILURE ); } std::vector< char > buffer( std::max( SEGY_TEXT_HEADER_SIZE, trsize ) ); /* copy textual header */ auto sz = std::fread( buffer.data(), 1, SEGY_TEXT_HEADER_SIZE, in ); if( sz != SEGY_TEXT_HEADER_SIZE ) { std::perror( "error reading text header" ); std::exit( EXIT_FAILURE ); } sz = std::fwrite( buffer.data(), 1, SEGY_TEXT_HEADER_SIZE, out ); if( sz != SEGY_TEXT_HEADER_SIZE ) { std::perror( "error writing text header" ); std::exit( EXIT_FAILURE ); } sz = std::fread( buffer.data(), 1, SEGY_BINARY_HEADER_SIZE, in ); if( sz != SEGY_BINARY_HEADER_SIZE ) { std::perror( "error reading binary header" ); std::exit( EXIT_FAILURE ); } flip_binary_header( buffer.data() ); sz = std::fwrite( buffer.data(), 1, SEGY_BINARY_HEADER_SIZE, out ); if( sz != SEGY_BINARY_HEADER_SIZE ) { std::perror( "error writing binary header" ); std::exit( EXIT_FAILURE ); } for( int i = 0; i < ext; ++i ) { sz = std::fread( buffer.data(), 1, SEGY_TEXT_HEADER_SIZE, in ); if( sz != SEGY_TEXT_HEADER_SIZE ) { std::perror( "error reading ext text header" ); std::exit( EXIT_FAILURE ); } sz = std::fwrite( buffer.data(), 1, SEGY_TEXT_HEADER_SIZE, out ); if( sz != SEGY_TEXT_HEADER_SIZE ) { std::perror( "error writing ext text header" ); std::exit( EXIT_FAILURE ); } } while( true ) { /* * read-flip-write trace header */ sz = std::fread( buffer.data(), 1, SEGY_TRACE_HEADER_SIZE, in ); if( sz == 0 && std::feof( in ) ) break; if( sz != SEGY_TRACE_HEADER_SIZE ) { std::perror( "error reading trace header" ); std::exit( EXIT_FAILURE ); } flip_trace_header( buffer.data() ); sz = std::fwrite( buffer.data(), 1, SEGY_TRACE_HEADER_SIZE, out ); if( sz != SEGY_TRACE_HEADER_SIZE ) { std::perror( "error writing trace header" ); std::exit( EXIT_FAILURE ); } /* * read-flip-write trace data */ sz = std::fread( buffer.data(), 1, trsize, in ); if( sz != std::size_t( trsize ) ) { std::perror( "error reading trace header" ); std::exit( EXIT_FAILURE ); } flip_trace_data( buffer.data(), samples, samplesize ); sz = std::fwrite( buffer.data(), 1, trsize, out ); if( sz != std::size_t( trsize ) ) { std::perror( "error writing trace header" ); std::exit( EXIT_FAILURE ); } } std::fclose( in ); std::fclose( out ); } segyio-1.8.3/bandit.yml0000664000372000037200000000001713407674361014421 0ustar travistravisskips: ['B101']segyio-1.8.3/lib/0000775000372000037200000000000013407674361013205 5ustar travistravissegyio-1.8.3/lib/include/0000775000372000037200000000000013407674361014630 5ustar travistravissegyio-1.8.3/lib/include/segyio/0000775000372000037200000000000013407674361016127 5ustar travistravissegyio-1.8.3/lib/include/segyio/segy.h0000664000372000037200000005303013407674361017250 0ustar travistravis#ifndef SEGYIO_SEGY_H #define SEGYIO_SEGY_H #include #include #define SEGY_BINARY_HEADER_SIZE 400 #define SEGY_TEXT_HEADER_SIZE 3200 #define SEGY_TRACE_HEADER_SIZE 240 #ifdef __cplusplus extern "C" { #endif // __cplusplus /* * About signatures: * If a function returns `int` you can assume the return value is an error * code. 0 will always indicate success. If a function returns something else * than an int it's typically an operation that cannot fail assuming the passed * buffer is of the correct size. Any exceptions will be clearly stated. * * Function signatures are typically: * 1) input parameters * 2) output parameters * 3) low-level file structure information * * Output parameters are non-const pointers, input parameters are const * pointers or plain values. All functions are namespace-prefix'd with segy_. * Some functions return values, notably the family concerned with the binary * header such as segy_trace0, that should be used in consecutive segy function * calls that use the same name for one of its parameters. */ struct segy_file_handle; typedef struct segy_file_handle segy_file; segy_file* segy_open( const char* path, const char* mode ); int segy_mmap( segy_file* ); int segy_flush( segy_file*, bool async ); int segy_close( segy_file* ); /* binary header operations */ /* * The binheader buffer passed to these functions must be of *at least* * `segy_binheader_size`. Returns size, not an error code. */ int segy_binheader_size( void ); int segy_binheader( segy_file*, char* buf ); int segy_write_binheader( segy_file*, const char* buf ); /* * exception: the int returned is the number of samples (the segy standard only * allocates 2 octets for this, so it comfortably sits inside an int */ int segy_samples( const char* binheader ); /* * infer the interval between traces. this function tries to read the interval * from the binary header and the first trace header, and will fall back to the * `fallback` argument. */ int segy_sample_interval( segy_file*, float fallback , float* dt ); /* exception: the int returned is an enum, SEGY_FORMAT, not an error code */ int segy_format( const char* binheader ); /* override the assumed format of the samples. * set file as LSB/MSB (little/big endian) * * by default, segyio assumes a 4-byte float format (usually IBM float). The * to/from native functions take this parameter explicitly, but functions like * read_subtrace requires the size of each element. * * `format` is the SEGY_FORMAT and SEGY_FILEOPT enum. if this function is not * called, for backwards compatibility reasons, the format is always assumed to * be IBM float. * * The binary header is not implicitly queried, because it's often broken and * unreliable with this information - however, if the header IS considered to * be reliable, the result of `segy_format` can be passed to this function. * * By default, segyio assumes files are MSB. However, some files (seismic unix, * SEG-Y rev2) are LSB. *all* functions returning bytes in segyio will output * MSB, regardless of the properties of the underlying file. * * independent format flags can be OR'd together: * segy_set_format( SEGY_IEEE_FLOAT_4_BYTE | SEGY_LSB ); */ int segy_set_format( segy_file*, int format ); int segy_get_field( const char* traceheader, int field, int32_t* f ); int segy_get_bfield( const char* binheader, int field, int32_t* f ); int segy_set_field( char* traceheader, int field, int32_t val ); int segy_set_bfield( char* binheader, int field, int32_t val ); int segy_field_forall( segy_file*, int field, int start, int stop, int step, int* buf, long trace0, int trace_bsize ); /* * exception: segy_trace_bsize computes the size of the traces in bytes. Cannot * fail. Equivalent to segy_trsize(SEGY_IBM_FLOAT_4_BYTE, samples); */ int segy_trace_bsize( int samples ); /* * segy_trsize computes the size of a trace in bytes, determined by the trace * format. If format is unknown, invalid, or unsupported, this function returns * a negative value. If `samples` is zero or negative, the result is undefined. */ int segy_trsize( int format, int samples ); /* byte-offset of the first trace header. */ long segy_trace0( const char* binheader ); /* * number of traces in this file. * if this function fails, the input argument is not modified. */ int segy_traces( segy_file*, int*, long trace0, int trace_bsize ); int segy_sample_indices( segy_file*, float t0, float dt, int count, float* buf ); /* text header operations */ /* buf in all read functions should be minimum segy_textheader_size() in size */ /* all read_textheader function outputs are zero-terminated C strings */ int segy_read_textheader( segy_file*, char *buf); int segy_textheader_size( void ); /* * read the extended textual headers. `pos = 0` gives the first *extended* * header, i.e. the first textual header following the binary header. * Behaviour is undefined if the file does not have extended headers */ int segy_read_ext_textheader( segy_file*, int pos, char* buf ); int segy_write_textheader( segy_file*, int pos, const char* buf ); /* Read the trace header at `traceno` into `buf`. */ int segy_traceheader( segy_file*, int traceno, char* buf, long trace0, int trace_bsize ); /* Read the trace header at `traceno` into `buf`. */ int segy_write_traceheader( segy_file*, int traceno, const char* buf, long trace0, int trace_bsize ); /* * The sorting type will be written to `sorting` if the function can figure out * how the file is sorted. */ int segy_sorting( segy_file*, int il, int xl, int tr_offset, int* sorting, long trace0, int trace_bsize ); /* * Number of offsets in this file, written to `offsets`. 1 if a 3D data set, >1 * if a 4D data set. */ int segy_offsets( segy_file*, int il, int xl, int traces, int* out, long trace0, int trace_bsize ); /* * The names of the individual offsets. `out` must be a buffer of * `segy_offsets` elements. */ int segy_offset_indices( segy_file*, int offset_field, int offsets, int* out, long trace0, int trace_bsize ); /* * read/write traces. does not convert data from on-disk representation to * native formats, so this data can not be used directly on most systems (intel * in particular). use to/from native to convert to native representations. */ int segy_readtrace( segy_file*, int traceno, void* buf, long trace0, int trace_bsize ); int segy_writetrace( segy_file*, int traceno, const void* buf, long trace0, int trace_bsize ); /* * read/write sub traces, with the same assumption and requirements as * segy_readtrace. start and stop are *indices*, not byte offsets, so * segy_readsubtr(fp, traceno, 10, 12, ...) reads samples 10 through 12, and * not bytes 10 through 12. * * start and stop are in the range [start,stop), so start=0, stop=5, step=2 * yields [0, 2, 4], whereas stop=4 yields [0, 2] * * When step is negative, the subtrace will be read in reverse. If step is * negative and [0,n) is desired, pass use -1 for stop. Other negative values * are undefined. If the range [n, m) where m is larger than the samples is * considered undefined. Any [n, m) where distance(n,m) > samples is undefined. * * The parameter rangebuf is a pointer to a buffer of at least abs(stop-start) * size. This is largely intended for script-C boundaries. In code paths where * step is not 1 or -1, and mmap is not activated, these functions will * *allocate* a buffer to read data from file in chunks. This is a significant * speedup over multiple fread calls, at the cost of a clunkier interface. This * is a tradeoff, since this function is often called in an inner loop. If * you're fine with these functions allocating and freeing this buffer for you, * rangebuf can be NULL. */ int segy_readsubtr( segy_file*, int traceno, int start, int stop, int step, void* buf, void* rangebuf, long trace0, int trace_bsize ); int segy_writesubtr( segy_file*, int traceno, int start, int stop, int step, const void* buf, void* rangebuf, long trace0, int trace_bsize ); /* * convert to/from native float from segy formats (likely IBM or IEEE). Size * parameter is long long because it needs to know the number of *samples*, * which can be very large for bulk conversion of a collection of traces. * * to/from native are unaware of the host architecture, and always assume MSB * layout. However, the read/write functions of segyio are aware, so as long as * only segyio functions are used, you do not need to care about the endianenss * of your platform. Some care must be taken, because you need to explicitly * tell segyio if your file uses LSB. */ int segy_to_native( int format, long long size, void* buf ); int segy_from_native( int format, long long size, void* buf ); int segy_read_line( segy_file* fp, int line_trace0, int line_length, int stride, int offsets, void* buf, long trace0, int trace_bsize ); int segy_write_line( segy_file* fp, int line_trace0, int line_length, int stride, int offsets, const void* buf, long trace0, int trace_bsize ); /* * Count inlines and crosslines. Use this function to determine how large buffer * the functions `segy_inline_indices` and `segy_crossline_indices` expect. If * the file is sorted on inlines, `field` should the trace header field for the * crossline number, and the inline number if the file is sorted on crosslines. * If the file is sorted on inlines, `l1out` will contain the number of * inlines, and `l2out` crosslines, and the other way around if the file is * sorted on crosslines. * * `offsets` is the number of offsets in the file and be found with * `segy_offsets`. * * If the file has only 1 trace (or, for pre-stack files, 1-trace-per-offset), * segyio considers this as 1 line in each direction. */ int segy_count_lines( segy_file*, int field, int offsets, int* l1out, int* l2out, long trace0, int trace_bsize ); /* * Alternative interface for segy_count_lines. If you have information about * sorting this is easier to use, but requires both the inline and crossline * header field positions. Does the argument shuffling needed to call * segy_count_lines. */ int segy_lines_count( segy_file*, int il, int xl, int sorting, int offsets, int* il_count, int* xl_count, long trace0, int trace_bsize ); /* * Find the `line_length` for the inlines. Assumes all inlines, crosslines and * traces don't vary in length. * * `inline_count` and `crossline_count` are the two values obtained with * `segy_count_lines`. * * These functions cannot fail and return the length, not an error code. */ int segy_inline_length(int crossline_count); int segy_crossline_length(int inline_count); /* * Find the indices of the inlines and write to `buf`. `offsets` are the number * of offsets for this file as returned by `segy_offsets` */ int segy_inline_indices( segy_file*, int il, int sorting, int inline_count, int crossline_count, int offsets, int* buf, long trace0, int trace_bsize ); int segy_crossline_indices( segy_file*, int xl, int sorting, int inline_count, int crossline_count, int offsets, int* buf, long trace0, int trace_bsize ); /* * Find the first `traceno` of the line `lineno`. `linenos` should be the line * indices returned by `segy_inline_indices` or `segy_crossline_indices`. The * stride depends on the sorting and is given by `segy_inline_stride` or * `segy_crossline_stride`. `offsets` is given by `segy_offsets` function, and * is the number of offsets in this file (1 for post stack data). `line_length` * is the length, i.e. traces per line, given by `segy_inline_length` or * `segy_crossline_length`. * * To read/write an inline, read `line_length` starting at `traceno`, * incrementing `traceno` with `stride` `line_length` times. */ int segy_line_trace0( int lineno, int line_length, int stride, int offsets, const int* linenos, int linenos_sz, int* traceno ); /* * Find the `rotation` of the survey in radians. * * Returns the clock-wise rotation around north, i.e. the angle between the * first line given and north axis. In this context, north is the direction * that yields a higher CDP-Y coordinate, and east is the direction that yields * a higher CDP-X coordinate. * * N * | * | * | + * | |~~/``````/ * | | /------/ * | |/,,,,,,/ * | * +--------------- E * * * When the survey is as depicted, and the first line is starting in the * south-west corner and goes north, the angle (~~) is < pi/4. If the first * line is parallel with equator moving east, the angle is pi/2. * * The return value is in the domain [0, 2pi) */ int segy_rotation_cw( segy_file*, int line_length, int stride, int offsets, const int* linenos, int linenos_sz, float* rotation, long trace0, int trace_bsize ); /* * Find the stride needed for an inline/crossline traversal. */ int segy_inline_stride( int sorting, int inline_count, int* stride ); int segy_crossline_stride( int sorting, int crossline_count, int* stride ); typedef enum { SEGY_TR_SEQ_LINE = 1, SEGY_TR_SEQ_FILE = 5, SEGY_TR_FIELD_RECORD = 9, SEGY_TR_NUMBER_ORIG_FIELD = 13, SEGY_TR_ENERGY_SOURCE_POINT = 17, SEGY_TR_ENSEMBLE = 21, SEGY_TR_NUM_IN_ENSEMBLE = 25, SEGY_TR_TRACE_ID = 29, SEGY_TR_SUMMED_TRACES = 31, SEGY_TR_STACKED_TRACES = 33, SEGY_TR_DATA_USE = 35, SEGY_TR_OFFSET = 37, SEGY_TR_RECV_GROUP_ELEV = 41, SEGY_TR_SOURCE_SURF_ELEV = 45, SEGY_TR_SOURCE_DEPTH = 49, SEGY_TR_RECV_DATUM_ELEV = 53, SEGY_TR_SOURCE_DATUM_ELEV = 57, SEGY_TR_SOURCE_WATER_DEPTH = 61, SEGY_TR_GROUP_WATER_DEPTH = 65, SEGY_TR_ELEV_SCALAR = 69, SEGY_TR_SOURCE_GROUP_SCALAR = 71, SEGY_TR_SOURCE_X = 73, SEGY_TR_SOURCE_Y = 77, SEGY_TR_GROUP_X = 81, SEGY_TR_GROUP_Y = 85, SEGY_TR_COORD_UNITS = 89, SEGY_TR_WEATHERING_VELO = 91, SEGY_TR_SUBWEATHERING_VELO = 93, SEGY_TR_SOURCE_UPHOLE_TIME = 95, SEGY_TR_GROUP_UPHOLE_TIME = 97, SEGY_TR_SOURCE_STATIC_CORR = 99, SEGY_TR_GROUP_STATIC_CORR = 101, SEGY_TR_TOT_STATIC_APPLIED = 103, SEGY_TR_LAG_A = 105, SEGY_TR_LAG_B = 107, SEGY_TR_DELAY_REC_TIME = 109, SEGY_TR_MUTE_TIME_START = 111, SEGY_TR_MUTE_TIME_END = 113, SEGY_TR_SAMPLE_COUNT = 115, SEGY_TR_SAMPLE_INTER = 117, SEGY_TR_GAIN_TYPE = 119, SEGY_TR_INSTR_GAIN_CONST = 121, SEGY_TR_INSTR_INIT_GAIN = 123, SEGY_TR_CORRELATED = 125, SEGY_TR_SWEEP_FREQ_START = 127, SEGY_TR_SWEEP_FREQ_END = 129, SEGY_TR_SWEEP_LENGTH = 131, SEGY_TR_SWEEP_TYPE = 133, SEGY_TR_SWEEP_TAPERLEN_START = 135, SEGY_TR_SWEEP_TAPERLEN_END = 137, SEGY_TR_TAPER_TYPE = 139, SEGY_TR_ALIAS_FILT_FREQ = 141, SEGY_TR_ALIAS_FILT_SLOPE = 143, SEGY_TR_NOTCH_FILT_FREQ = 145, SEGY_TR_NOTCH_FILT_SLOPE = 147, SEGY_TR_LOW_CUT_FREQ = 149, SEGY_TR_HIGH_CUT_FREQ = 151, SEGY_TR_LOW_CUT_SLOPE = 153, SEGY_TR_HIGH_CUT_SLOPE = 155, SEGY_TR_YEAR_DATA_REC = 157, SEGY_TR_DAY_OF_YEAR = 159, SEGY_TR_HOUR_OF_DAY = 161, SEGY_TR_MIN_OF_HOUR = 163, SEGY_TR_SEC_OF_MIN = 165, SEGY_TR_TIME_BASE_CODE = 167, SEGY_TR_WEIGHTING_FAC = 169, SEGY_TR_GEOPHONE_GROUP_ROLL1 = 171, SEGY_TR_GEOPHONE_GROUP_FIRST = 173, SEGY_TR_GEOPHONE_GROUP_LAST = 175, SEGY_TR_GAP_SIZE = 177, SEGY_TR_OVER_TRAVEL = 179, SEGY_TR_CDP_X = 181, SEGY_TR_CDP_Y = 185, SEGY_TR_INLINE = 189, SEGY_TR_CROSSLINE = 193, SEGY_TR_SHOT_POINT = 197, SEGY_TR_SHOT_POINT_SCALAR = 201, SEGY_TR_MEASURE_UNIT = 203, SEGY_TR_TRANSDUCTION_MANT = 205, SEGY_TR_TRANSDUCTION_EXP = 209, SEGY_TR_TRANSDUCTION_UNIT = 211, SEGY_TR_DEVICE_ID = 213, SEGY_TR_SCALAR_TRACE_HEADER = 215, SEGY_TR_SOURCE_TYPE = 217, SEGY_TR_SOURCE_ENERGY_DIR_MANT = 219, SEGY_TR_SOURCE_ENERGY_DIR_EXP = 223, SEGY_TR_SOURCE_MEASURE_MANT = 225, SEGY_TR_SOURCE_MEASURE_EXP = 229, SEGY_TR_SOURCE_MEASURE_UNIT = 231, SEGY_TR_UNASSIGNED1 = 233, SEGY_TR_UNASSIGNED2 = 237 } SEGY_FIELD; typedef enum { SEGY_BIN_JOB_ID = 3201, SEGY_BIN_LINE_NUMBER = 3205, SEGY_BIN_REEL_NUMBER = 3209, SEGY_BIN_TRACES = 3213, SEGY_BIN_AUX_TRACES = 3215, SEGY_BIN_INTERVAL = 3217, SEGY_BIN_INTERVAL_ORIG = 3219, SEGY_BIN_SAMPLES = 3221, SEGY_BIN_SAMPLES_ORIG = 3223, SEGY_BIN_FORMAT = 3225, SEGY_BIN_ENSEMBLE_FOLD = 3227, SEGY_BIN_SORTING_CODE = 3229, SEGY_BIN_VERTICAL_SUM = 3231, SEGY_BIN_SWEEP_FREQ_START = 3233, SEGY_BIN_SWEEP_FREQ_END = 3235, SEGY_BIN_SWEEP_LENGTH = 3237, SEGY_BIN_SWEEP = 3239, SEGY_BIN_SWEEP_CHANNEL = 3241, SEGY_BIN_SWEEP_TAPER_START = 3243, SEGY_BIN_SWEEP_TAPER_END = 3245, SEGY_BIN_TAPER = 3247, SEGY_BIN_CORRELATED_TRACES = 3249, SEGY_BIN_BIN_GAIN_RECOVERY = 3251, SEGY_BIN_AMPLITUDE_RECOVERY = 3253, SEGY_BIN_MEASUREMENT_SYSTEM = 3255, SEGY_BIN_IMPULSE_POLARITY = 3257, SEGY_BIN_VIBRATORY_POLARITY = 3259, SEGY_BIN_UNASSIGNED1 = 3261, SEGY_BIN_SEGY_REVISION = 3501, SEGY_BIN_TRACE_FLAG = 3503, SEGY_BIN_EXT_HEADERS = 3505, SEGY_BIN_UNASSIGNED2 = 3507, } SEGY_BINFIELD; typedef enum { SEGY_IBM_FLOAT_4_BYTE = 1, SEGY_SIGNED_INTEGER_4_BYTE = 2, SEGY_SIGNED_SHORT_2_BYTE = 3, SEGY_FIXED_POINT_WITH_GAIN_4_BYTE = 4, // Obsolete SEGY_IEEE_FLOAT_4_BYTE = 5, SEGY_NOT_IN_USE_1 = 6, SEGY_NOT_IN_USE_2 = 7, SEGY_SIGNED_CHAR_1_BYTE = 8 } SEGY_FORMAT; typedef enum { SEGY_LSB = (1 << 8), SEGY_MSB = (1 << 9), } SEGY_FILEOPT; typedef enum { SEGY_UNKNOWN_SORTING = 0, SEGY_CROSSLINE_SORTING = 1, SEGY_INLINE_SORTING = 2, } SEGY_SORTING; typedef enum { SEGY_OK = 0, SEGY_FOPEN_ERROR, SEGY_FSEEK_ERROR, SEGY_FREAD_ERROR, SEGY_FWRITE_ERROR, SEGY_INVALID_FIELD, SEGY_INVALID_SORTING, SEGY_MISSING_LINE_INDEX, SEGY_INVALID_OFFSETS, SEGY_TRACE_SIZE_MISMATCH, SEGY_INVALID_ARGS, SEGY_MMAP_ERROR, SEGY_MMAP_INVALID, SEGY_READONLY, SEGY_NOTFOUND, } SEGY_ERROR; #ifdef __cplusplus } #endif // __cplusplus #endif //SEGYIO_SEGY_H segyio-1.8.3/lib/src/0000775000372000037200000000000013407674361013774 5ustar travistravissegyio-1.8.3/lib/src/segyio/0000775000372000037200000000000013407674361015273 5ustar travistravissegyio-1.8.3/lib/src/segyio/util.h0000664000372000037200000000125013407674361016417 0ustar travistravis#ifndef SEGYIO_UTILS_H #define SEGYIO_UTILS_H #include /* * Functions that are internal implementations detail, but exposed to the * testing utilities. These functions won't show up in the installed headers. */ #ifdef __cplusplus extern "C" { #endif // __cplusplus struct segy_file_handle; void ebcdic2ascii( const char* ebcdic, char* ascii ); void ascii2ebcdic( const char* ascii, char* ebcdic ); void ibm2ieee(void* to, const void* from); void ieee2ibm(void* to, const void* from); int segy_seek( struct segy_file_handle*, int, long, int ); long long segy_ftell( struct segy_file_handle* ); #ifdef __cplusplus } #endif // __cplusplus #endif //SEGYIO_UTILS_H segyio-1.8.3/lib/src/segy.def0000664000372000037200000000157613407674361015434 0ustar travistravisLIBRARY segyio EXPORTS segy_open segy_mmap segy_flush segy_close segy_binheader_size segy_binheader segy_write_binheader segy_samples segy_sample_interval segy_format segy_set_format segy_get_field segy_get_bfield segy_set_field segy_set_bfield segy_field_forall segy_trace_bsize segy_trsize segy_trace0 segy_traces segy_sample_indices segy_read_textheader segy_textheader_size segy_read_ext_textheader segy_write_textheader segy_traceheader segy_write_traceheader segy_sorting segy_offsets segy_offset_indices segy_readtrace segy_readsubtr segy_writetrace segy_writesubtr segy_to_native segy_from_native segy_read_line segy_write_line segy_count_lines segy_lines_count segy_inline_length segy_crossline_length segy_inline_indices segy_crossline_indices segy_line_trace0 segy_inline_stride segy_crossline_stride segy_rotation_cw segy_seek segy_ftell ebcdic2ascii ascii2ebcdic ieee2ibm ibm2ieee segyio-1.8.3/lib/src/segy.c0000664000372000037200000021104413407674361015111 0ustar travistravis#define _POSIX_SOURCE /* fileno */ /* 64-bit off_t in ftello */ #define _POSIX_C_SOURCE 200808L #define _FILE_OFFSET_BITS 64 #if defined(_WIN32) || defined(_MSC_VER) /* MultiByteToWideChar */ #include #endif #ifdef HAVE_MMAP #define _POSIX_SOURCE #include #endif //HAVE_MMAP #ifdef HAVE_SYS_STAT_H #include #include #endif //HAVE_SYS_STAT_H #include #include #include #include #include #include #include #include #include static const unsigned char a2e[256] = { 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, 64, 79, 127,123,91, 108,80, 125,77, 93, 92, 78, 107,96, 75, 97, 240,241,242,243,244,245,246,247,248,249,122,94, 76, 126,110,111, 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, 215,216,217,226,227,228,229,230,231,232,233,74, 224,90, 95, 109, 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, 151,152,153,162,163,164,165,166,167,168,169,192,106,208,161,7, 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62, 225, 65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87, 88, 89, 98, 99, 100,101,102,103,104,105,112,113,114,115,116,117, 118,119,120,128,138,139,140,141,142,143,144,154,155,156,157,158, 159,160,170,171,172,173,174,175,176,177,178,179,180,181,182,183, 184,185,186,187,188,189,190,191,202,203,204,205,206,207,218,219, 220,221,222,223,234,235,236,237,238,239,250,251,252,253,254,255 }; static const unsigned char e2a[256] = { 0, 1, 2, 3, 156,9, 134,127,151,141,142, 11,12, 13, 14, 15, 16, 17, 18, 19, 157,133,8, 135,24, 25, 146,143,28, 29, 30, 31, 128,129,130,131,132,10, 23, 27, 136,137,138,139,140,5, 6, 7, 144,145,22, 147,148,149,150,4, 152,153,154,155,20, 21, 158,26, 32, 160,161,162,163,164,165,166,167,168,91, 46, 60, 40, 43, 33, 38, 169,170,171,172,173,174,175,176,177,93, 36, 42, 41, 59, 94, 45, 47, 178,179,180,181,182,183,184,185,124,44, 37, 95, 62, 63, 186,187,188,189,190,191,192,193,194,96, 58, 35, 64, 39, 61, 34, 195,97, 98, 99, 100,101,102,103,104,105,196,197,198,199,200,201, 202,106,107,108,109,110,111,112,113,114,203,204,205,206,207,208, 209,126,115,116,117,118,119,120,121,122,210,211,212,213,214,215, 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231, 123,65, 66, 67, 68, 69, 70, 71, 72, 73, 232,233,234,235,236,237, 125,74, 75, 76, 77, 78, 79, 80, 81, 82, 238,239,240,241,242,243, 92, 159,83, 84, 85, 86, 87, 88, 89, 90, 244,245,246,247,248,249, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 250,251,252,253,254,255 }; static int encode( char* dst, const char* src, const unsigned char* conv, size_t n ) { for( size_t i = 0; i < n; ++i ) dst[ i ] = (char)conv[ (unsigned char) src[ i ] ]; return SEGY_OK; } #ifdef HOST_BIG_ENDIAN #define HOST_LSB 0 #define HOST_MSB 1 #else #define HOST_LSB 1 #define HOST_MSB 0 #endif #if defined __GNUC__ #define bswap32(x) __builtin_bswap32((x)) #define bswap16(x) __builtin_bswap16((x)) #else #define bswap32(v) ( (((v) & 0x000000FF) << 24) \ | (((v) & 0x0000FF00) << 8) \ | (((v) & 0x00FF0000) >> 8) \ | (((v) & 0xFF000000) >> 24) \ ) #define bswap16(v) ( (((v) & 0x00FF) << 8) \ | (((v) & 0xFF00) >> 8) \ ) #endif // __GNUC__ static uint16_t htobe16( uint16_t v ) { #if HOST_LSB return bswap16(v); #else return v; #endif } static uint32_t htobe32( uint32_t v ) { #if HOST_LSB return bswap32(v); #else return v; #endif } static uint16_t be16toh( uint16_t v ) { #if HOST_LSB return bswap16(v); #else return v; #endif } static uint32_t be32toh( uint32_t v ) { #if HOST_LSB return bswap32(v); #else return v; #endif } /* * DEPRECATED * ebcdic2ascii and ascii2ebcdic are deprecated in favour of the length-aware * encode. They will be removed in segyio2. These functions were never public * (in the sense they're not available in headers), but currently have external * linkage. */ void ebcdic2ascii( const char* ebcdic, char* ascii ) { size_t len = strlen( ebcdic ); encode( ascii, ebcdic, e2a, len ); ascii[ len ] = '\0'; } void ascii2ebcdic( const char* ascii, char* ebcdic ) { size_t len = strlen( ascii ); encode( ebcdic, ascii, a2e, len ); ebcdic[ len ] = '\0'; } #define IEEEMAX 0x7FFFFFFF #define IEMAXIB 0x611FFFFF #define IEMINIB 0x21200000 static inline void ibm_native( void* buf ) { static int it[8] = { 0x21800000, 0x21400000, 0x21000000, 0x21000000, 0x20c00000, 0x20c00000, 0x20c00000, 0x20c00000 }; static int mt[8] = { 8, 4, 2, 2, 1, 1, 1, 1 }; unsigned int manthi, iexp, inabs; int ix; uint32_t u; memcpy( &u, buf, sizeof( u ) ); manthi = u & 0x00ffffff; ix = manthi >> 21; iexp = ( ( u & 0x7f000000 ) - it[ix] ) << 1; manthi = manthi * mt[ix] + iexp; inabs = u & 0x7fffffff; if ( inabs > IEMAXIB ) manthi = IEEEMAX; manthi = manthi | ( u & 0x80000000 ); u = ( inabs < IEMINIB ) ? 0 : manthi; memcpy( buf, &u, sizeof( u ) ); } static inline void native_ibm( void* buf ) { static int it[4] = { 0x21200000, 0x21400000, 0x21800000, 0x22100000 }; static int mt[4] = { 2, 4, 8, 1 }; unsigned int manthi, iexp, ix; uint32_t u; memcpy( &u, buf, sizeof( u ) ); ix = ( u & 0x01800000 ) >> 23; iexp = ( ( u & 0x7e000000 ) >> 1 ) + it[ix]; manthi = ( mt[ix] * ( u & 0x007fffff) ) >> 3; manthi = ( manthi + iexp ) | ( u & 0x80000000 ); u = ( u & 0x7fffffff ) ? manthi : 0; memcpy( buf, &u, sizeof( u ) ); } void ibm2ieee( void* to, const void* from ) { uint32_t u; memcpy( &u, from, sizeof( u ) ); u = be32toh( u ); ibm_native( &u ); memcpy( to, &u, sizeof( u ) ); } void ieee2ibm( void* to, const void* from ) { uint32_t u; memcpy( &u, from, sizeof( u ) ); native_ibm( &u ); u = be32toh( u ); memcpy( to, &u, sizeof( u ) ); } /* Lookup table for field sizes. All values not explicitly set are 0 */ static int field_size[] = { [SEGY_TR_CDP_X ] = 4, [SEGY_TR_CDP_Y ] = 4, [SEGY_TR_CROSSLINE ] = 4, [SEGY_TR_ENERGY_SOURCE_POINT ] = 4, [SEGY_TR_ENSEMBLE ] = 4, [SEGY_TR_FIELD_RECORD ] = 4, [SEGY_TR_GROUP_WATER_DEPTH ] = 4, [SEGY_TR_GROUP_X ] = 4, [SEGY_TR_GROUP_Y ] = 4, [SEGY_TR_INLINE ] = 4, [SEGY_TR_NUMBER_ORIG_FIELD ] = 4, [SEGY_TR_NUM_IN_ENSEMBLE ] = 4, [SEGY_TR_OFFSET ] = 4, [SEGY_TR_RECV_DATUM_ELEV ] = 4, [SEGY_TR_RECV_GROUP_ELEV ] = 4, [SEGY_TR_SEQ_FILE ] = 4, [SEGY_TR_SEQ_LINE ] = 4, [SEGY_TR_SHOT_POINT ] = 4, [SEGY_TR_SOURCE_DATUM_ELEV ] = 4, [SEGY_TR_SOURCE_DEPTH ] = 4, [SEGY_TR_SOURCE_ENERGY_DIR_MANT ] = 4, [SEGY_TR_SOURCE_MEASURE_MANT ] = 4, [SEGY_TR_SOURCE_SURF_ELEV ] = 4, [SEGY_TR_SOURCE_X ] = 4, [SEGY_TR_SOURCE_Y ] = 4, [SEGY_TR_TRANSDUCTION_MANT ] = 4, [SEGY_TR_UNASSIGNED1 ] = 4, [SEGY_TR_UNASSIGNED2 ] = 4, [SEGY_TR_ALIAS_FILT_FREQ ] = 2, [SEGY_TR_ALIAS_FILT_SLOPE ] = 2, [SEGY_TR_COORD_UNITS ] = 2, [SEGY_TR_CORRELATED ] = 2, [SEGY_TR_DATA_USE ] = 2, [SEGY_TR_DAY_OF_YEAR ] = 2, [SEGY_TR_DELAY_REC_TIME ] = 2, [SEGY_TR_DEVICE_ID ] = 2, [SEGY_TR_ELEV_SCALAR ] = 2, [SEGY_TR_GAIN_TYPE ] = 2, [SEGY_TR_GAP_SIZE ] = 2, [SEGY_TR_GEOPHONE_GROUP_FIRST ] = 2, [SEGY_TR_GEOPHONE_GROUP_LAST ] = 2, [SEGY_TR_GEOPHONE_GROUP_ROLL1 ] = 2, [SEGY_TR_GROUP_STATIC_CORR ] = 2, [SEGY_TR_GROUP_UPHOLE_TIME ] = 2, [SEGY_TR_HIGH_CUT_FREQ ] = 2, [SEGY_TR_HIGH_CUT_SLOPE ] = 2, [SEGY_TR_HOUR_OF_DAY ] = 2, [SEGY_TR_INSTR_GAIN_CONST ] = 2, [SEGY_TR_INSTR_INIT_GAIN ] = 2, [SEGY_TR_LAG_A ] = 2, [SEGY_TR_LAG_B ] = 2, [SEGY_TR_LOW_CUT_FREQ ] = 2, [SEGY_TR_LOW_CUT_SLOPE ] = 2, [SEGY_TR_MEASURE_UNIT ] = 2, [SEGY_TR_MIN_OF_HOUR ] = 2, [SEGY_TR_MUTE_TIME_END ] = 2, [SEGY_TR_MUTE_TIME_START ] = 2, [SEGY_TR_NOTCH_FILT_FREQ ] = 2, [SEGY_TR_NOTCH_FILT_SLOPE ] = 2, [SEGY_TR_OVER_TRAVEL ] = 2, [SEGY_TR_SAMPLE_COUNT ] = 2, [SEGY_TR_SAMPLE_INTER ] = 2, [SEGY_TR_SCALAR_TRACE_HEADER ] = 2, [SEGY_TR_SEC_OF_MIN ] = 2, [SEGY_TR_SHOT_POINT_SCALAR ] = 2, [SEGY_TR_SOURCE_ENERGY_DIR_EXP ] = 2, [SEGY_TR_SOURCE_GROUP_SCALAR ] = 2, [SEGY_TR_SOURCE_MEASURE_EXP ] = 2, [SEGY_TR_SOURCE_MEASURE_UNIT ] = 2, [SEGY_TR_SOURCE_STATIC_CORR ] = 2, [SEGY_TR_SOURCE_TYPE ] = 2, [SEGY_TR_SOURCE_UPHOLE_TIME ] = 2, [SEGY_TR_SOURCE_WATER_DEPTH ] = 2, [SEGY_TR_STACKED_TRACES ] = 2, [SEGY_TR_SUBWEATHERING_VELO ] = 2, [SEGY_TR_SUMMED_TRACES ] = 2, [SEGY_TR_SWEEP_FREQ_END ] = 2, [SEGY_TR_SWEEP_FREQ_START ] = 2, [SEGY_TR_SWEEP_LENGTH ] = 2, [SEGY_TR_SWEEP_TAPERLEN_END ] = 2, [SEGY_TR_SWEEP_TAPERLEN_START ] = 2, [SEGY_TR_SWEEP_TYPE ] = 2, [SEGY_TR_TAPER_TYPE ] = 2, [SEGY_TR_TIME_BASE_CODE ] = 2, [SEGY_TR_TOT_STATIC_APPLIED ] = 2, [SEGY_TR_TRACE_ID ] = 2, [SEGY_TR_TRANSDUCTION_EXP ] = 2, [SEGY_TR_TRANSDUCTION_UNIT ] = 2, [SEGY_TR_WEATHERING_VELO ] = 2, [SEGY_TR_WEIGHTING_FAC ] = 2, [SEGY_TR_YEAR_DATA_REC ] = 2, }; #define HEADER_SIZE SEGY_TEXT_HEADER_SIZE /* * Supporting same byte offsets as in the segy specification, i.e. from the * start of the *text header*, not the binary header. */ static int bfield_size[] = { [- HEADER_SIZE + SEGY_BIN_JOB_ID ] = 4, [- HEADER_SIZE + SEGY_BIN_LINE_NUMBER ] = 4, [- HEADER_SIZE + SEGY_BIN_REEL_NUMBER ] = 4, [- HEADER_SIZE + SEGY_BIN_TRACES ] = 2, [- HEADER_SIZE + SEGY_BIN_AUX_TRACES ] = 2, [- HEADER_SIZE + SEGY_BIN_INTERVAL ] = 2, [- HEADER_SIZE + SEGY_BIN_INTERVAL_ORIG ] = 2, [- HEADER_SIZE + SEGY_BIN_SAMPLES ] = 2, [- HEADER_SIZE + SEGY_BIN_SAMPLES_ORIG ] = 2, [- HEADER_SIZE + SEGY_BIN_FORMAT ] = 2, [- HEADER_SIZE + SEGY_BIN_ENSEMBLE_FOLD ] = 2, [- HEADER_SIZE + SEGY_BIN_SORTING_CODE ] = 2, [- HEADER_SIZE + SEGY_BIN_VERTICAL_SUM ] = 2, [- HEADER_SIZE + SEGY_BIN_SWEEP_FREQ_START ] = 2, [- HEADER_SIZE + SEGY_BIN_SWEEP_FREQ_END ] = 2, [- HEADER_SIZE + SEGY_BIN_SWEEP_LENGTH ] = 2, [- HEADER_SIZE + SEGY_BIN_SWEEP ] = 2, [- HEADER_SIZE + SEGY_BIN_SWEEP_CHANNEL ] = 2, [- HEADER_SIZE + SEGY_BIN_SWEEP_TAPER_START ] = 2, [- HEADER_SIZE + SEGY_BIN_SWEEP_TAPER_END ] = 2, [- HEADER_SIZE + SEGY_BIN_TAPER ] = 2, [- HEADER_SIZE + SEGY_BIN_CORRELATED_TRACES ] = 2, [- HEADER_SIZE + SEGY_BIN_BIN_GAIN_RECOVERY ] = 2, [- HEADER_SIZE + SEGY_BIN_AMPLITUDE_RECOVERY ] = 2, [- HEADER_SIZE + SEGY_BIN_MEASUREMENT_SYSTEM ] = 2, [- HEADER_SIZE + SEGY_BIN_IMPULSE_POLARITY ] = 2, [- HEADER_SIZE + SEGY_BIN_VIBRATORY_POLARITY ] = 2, [- HEADER_SIZE + SEGY_BIN_SEGY_REVISION ] = 2, [- HEADER_SIZE + SEGY_BIN_TRACE_FLAG ] = 2, [- HEADER_SIZE + SEGY_BIN_EXT_HEADERS ] = 2, [- HEADER_SIZE + SEGY_BIN_UNASSIGNED1 ] = 0, [- HEADER_SIZE + SEGY_BIN_UNASSIGNED2 ] = 0, }; /* * Determine the file size in bytes. If this function succeeds, the file * pointer will be reset to wherever it was before this call. If this call * fails for some reason, the return value is 0 and the file pointer location * will be determined by the behaviour of fseek. * * sys/stat.h is POSIX, but is well enough supported by Windows. The long long * data type is required to support files >4G (as long only guarantees 32 bits). */ #ifdef HAVE_SYS_STAT_H static int file_size( FILE* fp, long long* size ) { /* * the file size will be unaccurate unless userland buffers are flushed if * the file is new or appended to */ if( fflush( fp ) != 0 ) return SEGY_FWRITE_ERROR; #ifdef HAVE_FSTATI64 // this means we're on windows where fstat is unreliable for filesizes >2G // because long is only 4 bytes struct _stati64 st; const int err = _fstati64( fileno( fp ), &st ); #else struct stat st; const int err = fstat( fileno( fp ), &st ); #endif if( err != 0 ) return SEGY_FSEEK_ERROR; *size = st.st_size; return SEGY_OK; } #endif //HAVE_SYS_STAT_H static int formatsize( int format ) { switch( format ) { case SEGY_IBM_FLOAT_4_BYTE: return 4; case SEGY_SIGNED_INTEGER_4_BYTE: return 4; case SEGY_SIGNED_SHORT_2_BYTE: return 2; case SEGY_FIXED_POINT_WITH_GAIN_4_BYTE: return 4; case SEGY_IEEE_FLOAT_4_BYTE: return 4; case SEGY_SIGNED_CHAR_1_BYTE: return 1; case SEGY_NOT_IN_USE_1: case SEGY_NOT_IN_USE_2: default: return -1; } } /* * addr is NULL if mmap is not found under compilation or if the file is * not requested mmap'd. If so, the fallback code path of FILE* is taken */ #define MODEBUF_SIZE 5 struct segy_file_handle { void* addr; void* cur; FILE* fp; size_t fsize; char mode[ MODEBUF_SIZE ]; int writable; int elemsize; int lsb; }; segy_file* segy_open( const char* path, const char* mode ) { if( !path || !mode ) return NULL; // append a 'b' if it is not passed by the user; not a problem on unix, but // windows and other platforms fail without it char binary_mode[ MODEBUF_SIZE ] = { 0 }; strncpy( binary_mode, mode, 3 ); size_t mode_len = strlen( binary_mode ); if( binary_mode[ mode_len - 1 ] != 'b' ) binary_mode[ mode_len ] = 'b'; // Account for invalid mode. On unix this is fine, but windows crashes the // process if mode is invalid if( !strstr( "rb" "wb" "ab" "r+b" "w+b" "a+b", binary_mode ) ) return NULL; #ifdef _WIN32 /* * fun with windows. * Reported in https://github.com/Statoil/segyio/issues/266 * * Windows uses UTF-16 internally, also for path names, and fopen does not * handle UTF-16 strings on Windows. It's assumed input is UTF-8 or ascii , * and a simple conversion to the UTF-16 (wchar_t) version with _wfopen * makes non-ascii paths work on Windows. */ wchar_t wmode[ MODEBUF_SIZE ] = { 0 }; mbstowcs( wmode, binary_mode, strlen( binary_mode ) ); /* * call MultiByteToWideChar twice, once to figure out the size of the * resulting wchar string, and once to do the actual conversion */ int wpathlen = MultiByteToWideChar( CP_UTF8, 0, path, -1, NULL, 0 ); wchar_t* wpath = calloc( wpathlen + 1, sizeof( wchar_t ) ); MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, wpathlen ); FILE* fp = _wfopen( wpath, wmode ); free( wpath ); #else FILE* fp = fopen( path, binary_mode ); #endif if( !fp ) return NULL; segy_file* file = calloc( 1, sizeof( segy_file ) ); if( !file ) { fclose( fp ); return NULL; } file->fp = fp; strcpy( file->mode, binary_mode ); bool rw = strstr( file->mode, "+" ) || strstr( file->mode, "w" ); if( rw ) file->writable = 1; // assume a size of 4-bytes-per-element, until the set_format function // tells us otherwise. file->elemsize = 4; return file; } int segy_mmap( segy_file* fp ) { #ifndef HAVE_MMAP return SEGY_MMAP_INVALID; #else /* don't re-map; i.e. multiple consecutive calls should be no-ops */ if( fp->addr ) return SEGY_OK; long long fsize; int err = file_size( fp->fp, &fsize ); if( err != 0 ) return SEGY_FSEEK_ERROR; const int prot = fp->writable ? PROT_READ | PROT_WRITE : PROT_READ; int fd = fileno( fp->fp ); void* addr = mmap( NULL, fsize, prot, MAP_SHARED, fd, 0 ); // cppcheck-suppress memleak if( addr == MAP_FAILED ) return SEGY_MMAP_ERROR; fp->addr = fp->cur = addr; fp->fsize = fsize; fclose(fp->fp); return SEGY_OK; #endif //HAVE_MMAP } int segy_flush( segy_file* fp, bool async ) { // flush is a no-op for read-only files if( !fp->writable ) return SEGY_OK; #ifdef HAVE_MMAP if( fp->addr ) { int flag = async ? MS_ASYNC : MS_SYNC; int syncerr = msync( fp->addr, fp->fsize, flag ); if( syncerr != 0 ) return syncerr; return SEGY_OK; } #endif //HAVE_MMAP int flusherr = fflush( fp->fp ); if( flusherr != 0 ) return SEGY_FWRITE_ERROR; return SEGY_OK; } long long segy_ftell( segy_file* fp ) { #ifdef HAVE_FTELLO off_t pos = ftello( fp->fp ); assert( pos != -1 ); return pos; #elif HAVE_FTELLI64 // assuming we're on windows. This function is a little rough, but only // meant for testing - it's not a part of the public interface. return _ftelli64( fp->fp ); #else assert( false ); #endif } int segy_close( segy_file* fp ) { int err = segy_flush( fp, false ); #ifdef HAVE_MMAP if( !fp->addr ) goto no_mmap; // let errors unmapping take preference over flush-errors, as it is far // more severe // cppcheck-suppress redundantAssignment err = munmap( fp->addr, fp->fsize ); if( err != 0 ) err = SEGY_MMAP_ERROR; free( fp ); return err; no_mmap: #endif //HAVE_MMAP fclose( fp->fp ); free( fp ); return err; } static int get_field( const char* header, const int* table, int field, int32_t* f ) { const int bsize = table[ field ]; uint32_t buf32 = 0; uint16_t buf16 = 0; switch( bsize ) { case 4: memcpy( &buf32, header + (field - 1), 4 ); *f = (int32_t)be32toh( buf32 ); return SEGY_OK; case 2: memcpy( &buf16, header + (field - 1), 2 ); *f = (int16_t)be16toh( buf16 ); return SEGY_OK; case 0: default: return SEGY_INVALID_FIELD; } } int segy_get_field( const char* traceheader, int field, int* f ) { if( field < 0 || field >= SEGY_TRACE_HEADER_SIZE ) return SEGY_INVALID_FIELD; return get_field( traceheader, field_size, field, f ); } int segy_get_bfield( const char* binheader, int field, int32_t* f ) { field -= SEGY_TEXT_HEADER_SIZE; if( field < 0 || field >= SEGY_BINARY_HEADER_SIZE ) return SEGY_INVALID_FIELD; return get_field( binheader, bfield_size, field, f ); } static int set_field( char* header, const int* table, int field, int32_t val ) { const int bsize = table[ field ]; uint32_t buf32; uint16_t buf16; switch( bsize ) { case 4: buf32 = htobe32( (uint32_t)val ); memcpy( header + (field - 1), &buf32, sizeof( buf32 ) ); return SEGY_OK; case 2: buf16 = htobe16( (uint16_t)val ); memcpy( header + (field - 1), &buf16, sizeof( buf16 ) ); return SEGY_OK; case 0: default: return SEGY_INVALID_FIELD; } } int segy_set_field( char* traceheader, int field, int val ) { if( field < 0 || field >= SEGY_TRACE_HEADER_SIZE ) return SEGY_INVALID_FIELD; return set_field( traceheader, field_size, field, val ); } int segy_set_bfield( char* binheader, int field, int val ) { field -= SEGY_TEXT_HEADER_SIZE; if( field < 0 || field >= SEGY_BINARY_HEADER_SIZE ) return SEGY_INVALID_FIELD; return set_field( binheader, bfield_size, field, val ); } static int slicelength( int start, int stop, int step ) { if( step == 0 ) return 0; if( ( step < 0 && stop >= start ) || ( step > 0 && start >= stop ) ) return 0; if( step < 0 ) return (stop - start + 1) / step + 1; /* * cppcheck 1.84 introduced a false-positive on this as a result of * value-flow analysis not realising that step can *never* be zero here, as * it would trigger the early return. */ // cppcheck-suppress zerodivcond return (stop - start - 1) / step + 1; } int segy_field_forall( segy_file* fp, int field, int start, int stop, int step, int* buf, long trace0, int trace_bsize ) { int err; // do a dummy-read of a zero-init'd buffer to check args int32_t f; char header[ SEGY_TRACE_HEADER_SIZE ] = { 0 }; err = segy_get_field( header, field, &f ); if( err != SEGY_OK ) return SEGY_INVALID_ARGS; int slicelen = slicelength( start, stop, step ); // check *once* that we don't look past the end-of-file // checking seek error inside the loop is a performance killer err = segy_seek( fp, start, trace0, trace_bsize ); if( err != SEGY_OK ) return err; const int end = start + step * (slicelen - 1); err = segy_seek( fp, end, trace0, trace_bsize ); if( err != SEGY_OK ) return err; const int lsb = fp->lsb; #ifdef HAVE_MMAP if( fp->addr ) { for( int i = start; slicelen > 0; i += step, ++buf, --slicelen ) { segy_seek( fp, i, trace0, trace_bsize ); get_field( fp->cur, field_size, field, &f ); if( lsb ) f = bswap32(f); *buf = f; } return SEGY_OK; } #endif //HAVE_MMAP /* * non-mmap path. Doing multiple freads is slow, so instead the *actual* * offset is computed, not just the start of the header, and that's copied * into the correct offset in our local buffer. Note that byte offsets are * exposed 1-indexed (to stay consistent with the specification), but the * buffers are 0-indexed. * * Always read 4 bytes to be sure, there's no significant cost difference. */ const int zfield = field - 1; for( int i = start; slicelen > 0; i += step, ++buf, --slicelen ) { err = segy_seek( fp, i, trace0 + zfield, trace_bsize ); if( err != 0 ) return SEGY_FSEEK_ERROR; size_t readc = fread( header + zfield, sizeof( uint32_t ), 1, fp->fp ); if( readc != 1 ) return SEGY_FREAD_ERROR; segy_get_field( header, field, &f ); if( lsb ) f = bswap32(f); *buf = f; } return SEGY_OK; } /* * memread/memwrite are small utilities to give reading/writing to * memory-mapped files fread/fwrite like behaviour and fail if going outside * the file. Returns SEGY_FREAD/WRITE_ERROR, so that functions that are * read-and-return can just return this function's result */ static int memread( void* dest, const segy_file* fp, const void* src, size_t n ) { const void* begin = fp->addr; const void* end = (const char*)fp->addr + fp->fsize; const void* srcend = (const char*)src + n; if( src < begin || src > end || srcend > end ) return SEGY_FREAD_ERROR; memcpy( dest, src, n ); return SEGY_OK; } static int memwrite( segy_file* fp, void* dest, const void* src, size_t n ) { const void* begin = fp->addr; const void* end = (const char*)fp->addr + fp->fsize; const void* destend = (const char*)dest + n; if( dest < begin || dest > end || destend > end ) return SEGY_FWRITE_ERROR; memcpy( dest, src, n ); return SEGY_OK; } static int bswap_bin( char* xs, int lsb ) { if( !lsb ) return SEGY_OK; const int bytes4[] = { SEGY_BIN_JOB_ID, SEGY_BIN_LINE_NUMBER, SEGY_BIN_REEL_NUMBER }; const int bytes4_len = sizeof(bytes4) / sizeof(int); for( int i = 0; i < bytes4_len; ++i ) { uint32_t v; const int offset = bytes4[ i ] - (HEADER_SIZE+1); memcpy( &v, xs + offset, sizeof( v ) ); v = bswap32( v ); memcpy( xs + offset, &v, sizeof( v ) ); } const int bytes2[] = { SEGY_BIN_TRACES, SEGY_BIN_AUX_TRACES, SEGY_BIN_INTERVAL, SEGY_BIN_INTERVAL_ORIG, SEGY_BIN_SAMPLES, SEGY_BIN_SAMPLES_ORIG, SEGY_BIN_FORMAT, SEGY_BIN_ENSEMBLE_FOLD, SEGY_BIN_SORTING_CODE, SEGY_BIN_VERTICAL_SUM, SEGY_BIN_SWEEP_FREQ_START, SEGY_BIN_SWEEP_FREQ_END, SEGY_BIN_SWEEP_LENGTH, SEGY_BIN_SWEEP, SEGY_BIN_SWEEP_CHANNEL, SEGY_BIN_SWEEP_TAPER_START, SEGY_BIN_SWEEP_TAPER_END, SEGY_BIN_TAPER, SEGY_BIN_CORRELATED_TRACES, SEGY_BIN_BIN_GAIN_RECOVERY, SEGY_BIN_AMPLITUDE_RECOVERY, SEGY_BIN_MEASUREMENT_SYSTEM, SEGY_BIN_IMPULSE_POLARITY, SEGY_BIN_VIBRATORY_POLARITY, SEGY_BIN_SEGY_REVISION, SEGY_BIN_TRACE_FLAG, SEGY_BIN_EXT_HEADERS, }; const int bytes2_len = sizeof( bytes2 ) / sizeof( int ); for( int i = 0; i < bytes2_len; ++i ) { uint16_t v; const int offset = bytes2[ i ] - (HEADER_SIZE+1); memcpy( &v, xs + offset, sizeof( v ) ); v = bswap16( v ); memcpy( xs + offset, &v, sizeof( v ) ); } return SEGY_OK; } int segy_binheader( segy_file* fp, char* buf ) { if( !fp ) return SEGY_INVALID_ARGS; #ifdef HAVE_MMAP if( fp->addr ) { char* src = (char*)fp->addr + SEGY_TEXT_HEADER_SIZE; const int len = SEGY_BINARY_HEADER_SIZE; const int err = memread( buf, fp, src, len ); if( err ) return err; /* successful and file was lsb - swap to present as msb */ return bswap_bin( buf, fp->lsb ); } #endif //HAVE_MMAP const int err = fseek( fp->fp, SEGY_TEXT_HEADER_SIZE, SEEK_SET ); if( err != 0 ) return SEGY_FSEEK_ERROR; const size_t read_count = fread( buf, 1, SEGY_BINARY_HEADER_SIZE, fp->fp ); if( read_count != SEGY_BINARY_HEADER_SIZE ) return SEGY_FREAD_ERROR; return bswap_bin( buf, fp->lsb ); } int segy_write_binheader( segy_file* fp, const char* buf ) { if( !fp->writable ) return SEGY_READONLY; char swapped[ SEGY_BINARY_HEADER_SIZE ]; memcpy( swapped, buf, SEGY_BINARY_HEADER_SIZE ); bswap_bin( swapped, fp->lsb ); #ifdef HAVE_MMAP if( fp->addr ) { char* dst = (char*)fp->addr + SEGY_TEXT_HEADER_SIZE; const int len = SEGY_BINARY_HEADER_SIZE; return memwrite( fp, dst, swapped, len ); } #endif //HAVE_MMAP const int err = fseek( fp->fp, SEGY_TEXT_HEADER_SIZE, SEEK_SET ); if( err != 0 ) return SEGY_FSEEK_ERROR; const size_t writec = fwrite( swapped, 1, sizeof( swapped ), fp->fp ); if( writec != SEGY_BINARY_HEADER_SIZE ) return SEGY_FWRITE_ERROR; return SEGY_OK; } int segy_format( const char* binheader ) { int32_t format = 0; segy_get_bfield( binheader, SEGY_BIN_FORMAT, &format ); return format; } int segy_set_format( segy_file* fp, int format ) { /* extract the low byte to figure out elemsize */ const int fmt = format & 0xFF; const int elemsize = formatsize( fmt ); if( fmt && elemsize <= 0 ) return SEGY_INVALID_ARGS; /* extract the high byte to figure out endianness */ switch( format & 0xFF00 ) { case 0: break; case SEGY_LSB: fp->lsb = 1; break; case SEGY_MSB: fp->lsb = 0; break; default: return SEGY_INVALID_ARGS; } /* * for exception safety, only update state once it's certain nothing * failed */ if( elemsize > 0 ) fp->elemsize = elemsize; return SEGY_OK; } int segy_samples( const char* binheader ) { int32_t samples = 0; segy_get_bfield( binheader, SEGY_BIN_SAMPLES, &samples ); return samples; } int segy_trace_bsize( int samples ) { assert( samples >= 0 ); return segy_trsize( SEGY_IBM_FLOAT_4_BYTE, samples ); } int segy_trsize( int format, int samples ) { const int elemsize = formatsize( format ); if( elemsize < 0 ) return -1; return samples * elemsize; } long segy_trace0( const char* binheader ) { int extra_headers = 0; segy_get_bfield( binheader, SEGY_BIN_EXT_HEADERS, &extra_headers ); return SEGY_TEXT_HEADER_SIZE + SEGY_BINARY_HEADER_SIZE + SEGY_TEXT_HEADER_SIZE * extra_headers; } int segy_seek( segy_file* fp, int trace, long trace0, int trace_bsize ) { trace_bsize += SEGY_TRACE_HEADER_SIZE; long long pos = (long long)trace0 + (trace * (long long)trace_bsize); #ifdef HAVE_MMAP if( fp->addr ) { /* * mmap fseek doesn't fail (it's just a pointer readjustment) and won't * set errno, in order to keep its behaviour consistent with fseek, * which can easily reposition itself past the end-of-file */ fp->cur = (char*)fp->addr + pos; return SEGY_OK; } #endif //HAVE_MMAP int err; #if LONG_MAX == LLONG_MAX assert( pos <= LONG_MAX ); err = fseek( fp->fp, (long)pos, SEEK_SET ); #else /* * If long is 32bit on our platform (hello, windows), we do skips according * to LONG_MAX and seek relative to our cursor rather than absolute on file * begin. */ err = SEGY_OK; rewind( fp->fp ); while( pos >= LONG_MAX && err == SEGY_OK ) { err = fseek( fp->fp, LONG_MAX, SEEK_CUR ); pos -= LONG_MAX; } if( err != 0 ) return SEGY_FSEEK_ERROR; assert( pos <= LONG_MAX ); err = fseek( fp->fp, (long)pos, SEEK_CUR ); #endif if( err != 0 ) return SEGY_FSEEK_ERROR; return SEGY_OK; } static int bswap_th( char* xs, int lsb ) { if( !lsb ) return SEGY_OK; const int bytes4[] = { SEGY_TR_CDP_X, SEGY_TR_CDP_Y, SEGY_TR_CROSSLINE, SEGY_TR_ENERGY_SOURCE_POINT, SEGY_TR_ENSEMBLE, SEGY_TR_FIELD_RECORD, SEGY_TR_GROUP_WATER_DEPTH, SEGY_TR_GROUP_X, SEGY_TR_GROUP_Y, SEGY_TR_INLINE, SEGY_TR_NUMBER_ORIG_FIELD, SEGY_TR_NUM_IN_ENSEMBLE, SEGY_TR_OFFSET, SEGY_TR_RECV_DATUM_ELEV, SEGY_TR_RECV_GROUP_ELEV, SEGY_TR_SEQ_FILE, SEGY_TR_SEQ_LINE, SEGY_TR_SHOT_POINT, SEGY_TR_SOURCE_DATUM_ELEV, SEGY_TR_SOURCE_DEPTH, SEGY_TR_SOURCE_ENERGY_DIR_MANT, SEGY_TR_SOURCE_MEASURE_MANT, SEGY_TR_SOURCE_SURF_ELEV, SEGY_TR_SOURCE_X, SEGY_TR_SOURCE_Y, SEGY_TR_TRANSDUCTION_MANT, }; const int bytes4_len = sizeof(bytes4) / sizeof(int); for( int i = 0; i < bytes4_len; ++i ) { uint32_t v; const int offset = bytes4[ i ] - 1; memcpy( &v, xs + offset, sizeof( v ) ); v = bswap32( v ); memcpy( xs + offset, &v, sizeof( v ) ); } const int bytes2[] = { SEGY_TR_ALIAS_FILT_FREQ, SEGY_TR_ALIAS_FILT_SLOPE, SEGY_TR_COORD_UNITS, SEGY_TR_CORRELATED, SEGY_TR_DATA_USE, SEGY_TR_DAY_OF_YEAR, SEGY_TR_DELAY_REC_TIME, SEGY_TR_DEVICE_ID, SEGY_TR_ELEV_SCALAR, SEGY_TR_GAIN_TYPE, SEGY_TR_GAP_SIZE, SEGY_TR_GEOPHONE_GROUP_FIRST, SEGY_TR_GEOPHONE_GROUP_LAST, SEGY_TR_GEOPHONE_GROUP_ROLL1, SEGY_TR_GROUP_STATIC_CORR, SEGY_TR_GROUP_UPHOLE_TIME, SEGY_TR_HIGH_CUT_FREQ, SEGY_TR_HIGH_CUT_SLOPE, SEGY_TR_HOUR_OF_DAY, SEGY_TR_INSTR_GAIN_CONST, SEGY_TR_INSTR_INIT_GAIN, SEGY_TR_LAG_A, SEGY_TR_LAG_B, SEGY_TR_LOW_CUT_FREQ, SEGY_TR_LOW_CUT_SLOPE, SEGY_TR_MEASURE_UNIT, SEGY_TR_MIN_OF_HOUR, SEGY_TR_MUTE_TIME_END, SEGY_TR_MUTE_TIME_START, SEGY_TR_NOTCH_FILT_FREQ, SEGY_TR_NOTCH_FILT_SLOPE, SEGY_TR_OVER_TRAVEL, SEGY_TR_SAMPLE_COUNT, SEGY_TR_SAMPLE_INTER, SEGY_TR_SCALAR_TRACE_HEADER, SEGY_TR_SEC_OF_MIN, SEGY_TR_SHOT_POINT_SCALAR, SEGY_TR_SOURCE_ENERGY_DIR_EXP, SEGY_TR_SOURCE_GROUP_SCALAR, SEGY_TR_SOURCE_MEASURE_EXP, SEGY_TR_SOURCE_MEASURE_UNIT, SEGY_TR_SOURCE_STATIC_CORR, SEGY_TR_SOURCE_TYPE, SEGY_TR_SOURCE_UPHOLE_TIME, SEGY_TR_SOURCE_WATER_DEPTH, SEGY_TR_STACKED_TRACES, SEGY_TR_SUBWEATHERING_VELO, SEGY_TR_SUMMED_TRACES, SEGY_TR_SWEEP_FREQ_END, SEGY_TR_SWEEP_FREQ_START, SEGY_TR_SWEEP_LENGTH, SEGY_TR_SWEEP_TAPERLEN_END, SEGY_TR_SWEEP_TAPERLEN_START, SEGY_TR_SWEEP_TYPE, SEGY_TR_TAPER_TYPE, SEGY_TR_TIME_BASE_CODE, SEGY_TR_TOT_STATIC_APPLIED, SEGY_TR_TRACE_ID, SEGY_TR_TRANSDUCTION_EXP, SEGY_TR_TRANSDUCTION_UNIT, SEGY_TR_WEATHERING_VELO, SEGY_TR_WEIGHTING_FAC, SEGY_TR_YEAR_DATA_REC, }; const int bytes2_len = sizeof( bytes2 ) / sizeof( int ); for( int i = 0; i < bytes2_len; ++i ) { uint16_t v; const int offset = bytes2[ i ] - 1; memcpy( &v, xs + offset, sizeof( v ) ); v = bswap16( v ); memcpy( xs + offset, &v, sizeof( v ) ); } return SEGY_OK; } int segy_traceheader( segy_file* fp, int traceno, char* buf, long trace0, int trace_bsize ) { const int err = segy_seek( fp, traceno, trace0, trace_bsize ); if( err != 0 ) return err; if( fp->addr ) { const int errm = memread( buf, fp, fp->cur, SEGY_TRACE_HEADER_SIZE ); if( errm ) return errm; return bswap_th( buf, fp->lsb ); } const size_t readc = fread( buf, 1, SEGY_TRACE_HEADER_SIZE, fp->fp ); if( readc != SEGY_TRACE_HEADER_SIZE ) return SEGY_FREAD_ERROR; return bswap_th( buf, fp->lsb ); } int segy_write_traceheader( segy_file* fp, int traceno, const char* buf, long trace0, int trace_bsize ) { if( !fp->writable ) return SEGY_READONLY; const int err = segy_seek( fp, traceno, trace0, trace_bsize ); if( err != 0 ) return err; char swapped[ SEGY_TRACE_HEADER_SIZE ]; memcpy( swapped, buf, SEGY_TRACE_HEADER_SIZE ); bswap_th( swapped, fp->lsb ); if( fp->addr ) return memwrite( fp, fp->cur, swapped, SEGY_TRACE_HEADER_SIZE ); const size_t writec = fwrite( swapped, 1, SEGY_TRACE_HEADER_SIZE, fp->fp ); if( writec != SEGY_TRACE_HEADER_SIZE ) return SEGY_FWRITE_ERROR; return SEGY_OK; } /* * Return the number of traces in the file. The file pointer won't change after * this call unless fseek itself fails. * * This function assumes that *all traces* are of the same size. */ int segy_traces( segy_file* fp, int* traces, long trace0, int trace_bsize ) { if( trace0 < 0 ) return SEGY_INVALID_ARGS; long long size; if( fp->addr ) size = fp->fsize; else{ int err = file_size( fp->fp, &size ); if( err != 0 ) return err; } if( trace0 > size ) return SEGY_INVALID_ARGS; size -= trace0; trace_bsize += SEGY_TRACE_HEADER_SIZE; if( size % trace_bsize != 0 ) return SEGY_TRACE_SIZE_MISMATCH; assert( size / trace_bsize <= (long long)INT_MAX ); *traces = size / trace_bsize; return SEGY_OK; } int segy_sample_interval( segy_file* fp, float fallback, float* dt ) { char bin_header[ SEGY_BINARY_HEADER_SIZE ]; char trace_header[ SEGY_TRACE_HEADER_SIZE ]; int err = segy_binheader( fp, bin_header ); if (err != 0) { return err; } const long trace0 = segy_trace0( bin_header ); /* we don't need to figure out a trace size, since we're not advancing * beyond the first header */ err = segy_traceheader(fp, 0, trace_header, trace0, 0); if (err != 0) { return err; } int32_t bindt = 0; int32_t trdt = 0; segy_get_bfield( bin_header, SEGY_BIN_INTERVAL, &bindt ); segy_get_field( trace_header, SEGY_TR_SAMPLE_INTER, &trdt ); float binary_header_dt = bindt; float trace_header_dt = trdt; /* * 3 cases: * * When the trace header and binary header disagree on a (non-zero) * sample interval; choose neither and opt for the fallback. * * When both sample intervals are zero: opt for the fallback. * * Otherwise, choose the interval from the non-zero header. */ *dt = fallback; if( binary_header_dt == 0 && trace_header_dt != 0 ) *dt = trace_header_dt; if( trace_header_dt == 0 && binary_header_dt != 0 ) *dt = binary_header_dt; if( trace_header_dt == binary_header_dt && trace_header_dt != 0 ) *dt = trace_header_dt; return SEGY_OK; } int segy_sample_indices( segy_file* fp, float t0, float dt, int count, float* buf ) { int err = segy_sample_interval(fp, dt, &dt); if (err != 0) { return err; } for( int i = 0; i < count; i++ ) { buf[i] = t0 + i * dt; } return SEGY_OK; } /* * Determine how a file is sorted. Expects the following three fields from the * trace header to guide sorting: the inline number `il`, the crossline * number `xl` and the offset number `tr_offset`. * * Iterates through trace headers and compare the three fields with the * fields from the previous header. If iline or crossline sorting is established * the method returns the sorting without reading through the rest of the file. * * A file is inline-sorted if inline is the last value to move. Likewise for * crossline sorted. If the file does not qualify as inline- or * crossline-sorted, it is unsorted. Exactly one of the three values should * increment from one trace to another for the file to be properly sorted. */ int segy_sorting( segy_file* fp, int il, int xl, int tr_offset, int* sorting, long trace0, int trace_bsize ) { int err; char traceheader[ SEGY_TRACE_HEADER_SIZE ]; err = segy_traceheader( fp, 0, traceheader, trace0, trace_bsize ); if( err != SEGY_OK ) return err; /* make sure field is valid, so we don't have to check errors later */ const int fields[] = { il, xl, tr_offset }; int len = sizeof( fields ) / sizeof( int ); for( int i = 0; i < len; ++i ) { const int f = fields[ i ]; if( f < 0 ) return SEGY_INVALID_FIELD; if( f >= SEGY_TRACE_HEADER_SIZE ) return SEGY_INVALID_FIELD; if( field_size[ f ] == 0 ) return SEGY_INVALID_FIELD; } int traces; err = segy_traces( fp, &traces, trace0, trace_bsize ); if( err ) return err; if( traces == 1 ) { *sorting = SEGY_CROSSLINE_SORTING; return SEGY_OK; } int il_first = 0, il_next = 0, il_prev = 0; int xl_first = 0, xl_next = 0, xl_prev = 0; int of_first = 0, of_next = 0; segy_get_field( traceheader, il, &il_first ); segy_get_field( traceheader, xl, &xl_first ); segy_get_field( traceheader, tr_offset, &of_first ); il_prev = il_first; xl_prev = xl_first; /* Iterating through traces, comparing il, xl, and offset values with the * values from the previous trace. Several cases is checked when * determining sorting: * If the offset have wrapped around and either il or xl is changed, * the sorting is xline or iline, respectivly. * If neither offset, il or xl changes, the file is unsorted. * If more than one value change from one trace to another, the file is * unsorted. */ int traceno = 1; while ( traceno < traces ) { err = segy_traceheader( fp, traceno, traceheader, trace0, trace_bsize ); if( err ) return err; ++traceno; segy_get_field( traceheader, il, &il_next ); segy_get_field( traceheader, xl, &xl_next ); segy_get_field( traceheader, tr_offset, &of_next ); /* the exit condition - offset has wrapped around. */ if( of_next == of_first ) { if( il_next == il_prev && xl_next != xl_prev ) { *sorting = SEGY_INLINE_SORTING; return SEGY_OK; } if( xl_next == xl_prev && il_next != il_prev ) { *sorting = SEGY_CROSSLINE_SORTING; return SEGY_OK; } *sorting = SEGY_UNKNOWN_SORTING; return SEGY_OK; } /* something else than offsets also moved, so this is not sorted */ if( il_prev != il_next ) { *sorting = SEGY_UNKNOWN_SORTING; return SEGY_OK; } if( xl_prev != xl_next ) { *sorting = SEGY_UNKNOWN_SORTING; return SEGY_OK; } } *sorting = SEGY_CROSSLINE_SORTING; return SEGY_OK; } /* * Find the number of offsets. This is determined by inspecting the trace * headers [0,n) where n is the first trace where either the inline number or * the crossline number changes (which changes first depends on sorting, but is * irrelevant for this function). */ int segy_offsets( segy_file* fp, int il, int xl, int traces, int* out, long trace0, int trace_bsize ) { int err; int il0 = 0, il1 = 0, xl0 = 0, xl1 = 0; char header[ SEGY_TRACE_HEADER_SIZE ]; int offsets = 0; if( traces == 1 ) { *out = 1; return SEGY_OK; } /* * check that field value is sane, so that we don't have to check * segy_get_field's error */ if( field_size[ il ] == 0 || field_size[ xl ] == 0 ) return SEGY_INVALID_FIELD; err = segy_traceheader( fp, 0, header, trace0, trace_bsize ); if( err != 0 ) return SEGY_FREAD_ERROR; segy_get_field( header, il, &il0 ); segy_get_field( header, xl, &xl0 ); do { ++offsets; if( offsets == traces ) break; err = segy_traceheader( fp, offsets, header, trace0, trace_bsize ); if( err != 0 ) return err; segy_get_field( header, il, &il1 ); segy_get_field( header, xl, &xl1 ); } while( il0 == il1 && xl0 == xl1 ); *out = offsets; return SEGY_OK; } int segy_offset_indices( segy_file* fp, int offset_field, int offsets, int* out, long trace0, int trace_bsize ) { int32_t x = 0; char header[ SEGY_TRACE_HEADER_SIZE ]; if( field_size[ offset_field ] == 0 ) return SEGY_INVALID_FIELD; for( int i = 0; i < offsets; ++i ) { const int err = segy_traceheader( fp, i, header, trace0, trace_bsize ); if( err != SEGY_OK ) return err; segy_get_field( header, offset_field, &x ); *out++ = x; } return SEGY_OK; } static int segy_line_indices( segy_file* fp, int field, int traceno, int stride, int num_indices, int* buf, long trace0, int trace_bsize ) { return segy_field_forall( fp, field, traceno, /* start */ traceno + (num_indices * stride), /* stop */ stride, /* step */ buf, trace0, trace_bsize ); } static int count_lines( segy_file* fp, int field, int offsets, int traces, int* out, long trace0, int trace_bsize ) { int err; char header[ SEGY_TRACE_HEADER_SIZE ]; err = segy_traceheader( fp, 0, header, trace0, trace_bsize ); if( err != 0 ) return err; int first_lineno, first_offset, ln = 0, off = 0; err = segy_get_field( header, field, &first_lineno ); if( err != 0 ) return err; err = segy_get_field( header, 37, &first_offset ); if( err != 0 ) return err; int lines = 1; int curr = offsets; while( true ) { if( curr == traces ) break; if( curr > traces ) return SEGY_NOTFOUND; err = segy_traceheader( fp, curr, header, trace0, trace_bsize ); if( err != 0 ) return err; segy_get_field( header, field, &ln ); segy_get_field( header, 37, &off ); if( first_offset == off && ln == first_lineno ) break; curr += offsets; ++lines; } *out = lines; return SEGY_OK; } int segy_count_lines( segy_file* fp, int field, int offsets, int* l1out, int* l2out, long trace0, int trace_bsize ) { int traces; int err = segy_traces( fp, &traces, trace0, trace_bsize ); if( err != 0 ) return err; /* * handle the case where there's only one trace (per offset) in the file, * and interpret is as a 1 line in each direction, with 1 trace (per * offset). */ if( traces == offsets ) { *l1out = *l2out = 1; return SEGY_OK; } int l2count; err = count_lines( fp, field, offsets, traces, &l2count, trace0, trace_bsize ); if( err != 0 ) return err; const int line_length = l2count * offsets; const int l1count = traces / line_length; *l1out = l1count; *l2out = l2count; return SEGY_OK; } int segy_lines_count( segy_file* fp, int il, int xl, int sorting, int offsets, int* il_count, int* xl_count, long trace0, int trace_bsize ) { if( sorting == SEGY_UNKNOWN_SORTING ) return SEGY_INVALID_SORTING; int field; int l1out, l2out; if( sorting == SEGY_INLINE_SORTING ) field = xl; else field = il; int err = segy_count_lines( fp, field, offsets, &l1out, &l2out, trace0, trace_bsize ); if( err != SEGY_OK ) return err; if( sorting == SEGY_INLINE_SORTING ) { *il_count = l1out; *xl_count = l2out; } else { *il_count = l2out; *xl_count = l1out; } return SEGY_OK; } /* * segy_*line_length is rather pointless as a computation, but serve a purpose * as an abstraction as the detail on how exactly a length is defined is usually uninteresting */ int segy_inline_length( int crossline_count ) { return crossline_count; } int segy_crossline_length( int inline_count ) { return inline_count; } int segy_inline_indices( segy_file* fp, int il, int sorting, int inline_count, int crossline_count, int offsets, int* buf, long trace0, int trace_bsize) { if( sorting == SEGY_INLINE_SORTING ) { int stride = crossline_count * offsets; return segy_line_indices( fp, il, 0, stride, inline_count, buf, trace0, trace_bsize ); } if( sorting == SEGY_CROSSLINE_SORTING ) { return segy_line_indices( fp, il, 0, offsets, inline_count, buf, trace0, trace_bsize ); } return SEGY_INVALID_SORTING; } int segy_crossline_indices( segy_file* fp, int xl, int sorting, int inline_count, int crossline_count, int offsets, int* buf, long trace0, int trace_bsize ) { if( sorting == SEGY_INLINE_SORTING ) { return segy_line_indices( fp, xl, 0, offsets, crossline_count, buf, trace0, trace_bsize ); } if( sorting == SEGY_CROSSLINE_SORTING ) { int stride = inline_count * offsets; return segy_line_indices( fp, xl, 0, stride, crossline_count, buf, trace0, trace_bsize ); } return SEGY_INVALID_SORTING; } static inline int subtr_seek( segy_file* fp, int traceno, int start, int stop, int elemsize, long trace0, int trace_bsize ) { /* * Optimistically assume that indices are correct by the time they're given * to subtr_seek. */ const int min = start < stop ? start : stop + 1; assert( start >= 0 ); assert( stop >= -1 ); assert( abs(stop - start) * elemsize <= trace_bsize ); // skip the trace header and skip everything before min trace0 += (min * elemsize) + SEGY_TRACE_HEADER_SIZE; return segy_seek( fp, traceno, trace0, trace_bsize ); } static int reverse( void* buf, int elems, int elemsize ) { char* arr = (char*) buf; const int last = elems - 1; char tmp[ 8 ]; for( int i = 0; i < elems / 2; ++i ) { memcpy( tmp, arr + i * elemsize, elemsize ); memcpy( arr + i * elemsize, arr + (last - i) * elemsize, elemsize ); memcpy( arr + (last - i) * elemsize, tmp, elemsize ); } return SEGY_OK; } int segy_readtrace( segy_file* fp, int traceno, void* buf, long trace0, int trace_bsize ) { const int stop = trace_bsize / fp->elemsize; return segy_readsubtr( fp, traceno, 0, stop, 1, buf, NULL, trace0, trace_bsize ); } static int bswap32vec( void* vec, long long len ) { char* begin = (char*) vec; char* end = (char*) begin + len * sizeof(int32_t); for( char* xs = begin; xs != end; xs += sizeof(int32_t) ) { uint32_t v; memcpy( &v, xs, sizeof(int32_t) ); v = bswap32( v ); memcpy( xs, &v, sizeof(int32_t) ); } return SEGY_OK; } static int bswap16vec( void* vec, long long len ) { char* begin = (char*) vec; char* end = (char*) begin + len * sizeof(int16_t); for( char* xs = begin; xs != end; xs += sizeof(int16_t) ) { uint16_t v; memcpy( &v, xs, sizeof(int16_t) ); v = bswap16( v ); memcpy( xs, &v, sizeof(int16_t) ); } return SEGY_OK; } int segy_readsubtr( segy_file* fp, int traceno, int start, int stop, int step, void* buf, void* rangebuf, long trace0, int trace_bsize ) { const int elems = abs( stop - start ); const int elemsize = fp->elemsize; int err = subtr_seek( fp, traceno, start, stop, elemsize, trace0, trace_bsize ); if( err != SEGY_OK ) return err; // most common case: step == abs(1), reading contiguously if( step == 1 || step == -1 ) { if( fp->addr ) { err = memread( buf, fp, fp->cur, elemsize * elems ); if( err != SEGY_OK ) return err; } else { const int readc = fread( buf, elemsize, elems, fp->fp ); if( readc != elems ) return SEGY_FREAD_ERROR; } if( fp->lsb && fp->elemsize == 4 ) bswap32vec( buf, elems ); if( fp->lsb && fp->elemsize == 2 ) bswap16vec( buf, elems ); if( step == -1 ) reverse( buf, elems, elemsize ); return SEGY_OK; } // step != 1, i.e. do strided reads int defstart = start < stop ? 0 : elems - 1; const int slicelen = slicelength( start, stop, step ); // step is the distance between elems to read, but now we're counting bytes step *= elemsize; char* dst = (char*)buf; if( fp->addr ) { const char* cur = (char*)fp->cur + elemsize * defstart; for( int i = 0; i < slicelen; cur += step, dst += elemsize, ++i ) memcpy( dst, cur, elemsize ); if( fp->lsb && fp->elemsize == 4 ) bswap32vec( buf, slicelen ); if( fp->lsb && fp->elemsize == 2 ) bswap16vec( buf, slicelen ); return SEGY_OK; } /* * fread fallback: read the full chunk [start, stop) to avoid multiple * fread calls (which are VERY expensive, measured to about 10x the cost of * a single read when reading every other trace). If rangebuf is NULL, the * caller has not supplied a buffer for us to use (likely if it's a * one-off, and we heap-alloc a buffer. This way the function is safer to * use, but with a significant performance penalty when no buffer is * supplied. */ void* tracebuf = rangebuf ? rangebuf : malloc( elems * elemsize ); const int readc = fread( tracebuf, elemsize, elems, fp->fp ); if( readc != elems ) { if( !rangebuf ) free( tracebuf ); return SEGY_FREAD_ERROR; } const char* cur = (char*)tracebuf + elemsize * defstart; for( int i = 0; i < slicelen; cur += step, ++i, dst += elemsize ) memcpy( dst, cur, elemsize ); if( fp->lsb && fp->elemsize == 4 ) bswap32vec( buf, slicelen ); if( fp->lsb && fp->elemsize == 2 ) bswap16vec( buf, slicelen ); if( !rangebuf ) free( tracebuf ); return SEGY_OK; } int segy_writetrace( segy_file* fp, int traceno, const void* buf, long trace0, int trace_bsize ) { const int stop = trace_bsize / fp->elemsize; return segy_writesubtr( fp, traceno, 0, stop, 1, buf, NULL, trace0, trace_bsize ); } static int bswap32vec_strided( char* dst, const char* src, int step, int len ) { const int elemsize = sizeof( int32_t ); step *= elemsize; uint32_t v; for( ; len > 0; dst += step, src += elemsize, --len ) { memcpy( &v, src, elemsize ); v = bswap32( v ); memcpy( dst, &v, elemsize ); } return SEGY_OK; } static int bswap16vec_strided( char* dst, const char* src, int step, int len ) { const int elemsize = sizeof( int16_t ); step *= elemsize; uint16_t v; for( ; len > 0; dst += step, src += elemsize, --len ) { memcpy( &v, src, elemsize ); v = bswap16( v ); memcpy( dst, &v, elemsize ); } return SEGY_OK; } int segy_writesubtr( segy_file* fp, int traceno, int start, int stop, int step, const void* buf, void* rangebuf, long trace0, int trace_bsize ) { if( !fp->writable ) return SEGY_READONLY; const int elems = abs( stop - start ); const int elemsize = fp->elemsize; int err = subtr_seek( fp, traceno, start, stop, elemsize, trace0, trace_bsize ); if( err != SEGY_OK ) return err; if( step == 1 && !fp->lsb ) { /* * most common case: step == 1, writing contiguously * -1 is not covered here as it would require reversing the input buffer * (which is const), which in turn may require a memory allocation. It will * be handled by the stride-aware code path */ if( fp->addr ) { err = memwrite( fp, fp->cur, buf, elemsize * elems ); if( err ) return err; } else { const int writec = fwrite( buf, elemsize, elems, fp->fp ); if( writec != elems ) return SEGY_FWRITE_ERROR; } return SEGY_OK; } /* * contiguous, but require memory either because reversing, or byte * swapping */ if( !fp->addr && (step == 1 || step == -1) && fp->lsb ) { void* tracebuf = rangebuf ? rangebuf : malloc( elems * elemsize ); memcpy( tracebuf, buf, elemsize * elems ); if( step == -1 ) reverse( tracebuf, elems, elemsize ); if( fp->lsb && elemsize == 4 ) bswap32vec( tracebuf, elems ); if( fp->lsb && elemsize == 2 ) bswap16vec( tracebuf, elems ); /* * only handle fstream path - the mmap is handled comfortably by the * stride-aware code path */ const int writec = fwrite( tracebuf, elemsize, elems, fp->fp ); if( !rangebuf ) free( tracebuf ); if( writec != elems ) return SEGY_FWRITE_ERROR; return SEGY_OK; } // step != 1, i.e. do strided reads int defstart = start < stop ? 0 : elems - 1; int slicelen = slicelength( start, stop, step ); // step is the distance between elems, but we're counting bytes const char* src = (const char*)buf; if( fp->addr ) { /* if mmap is on, strided write is trivial and fast */ char* cur = (char*)fp->cur + elemsize * defstart; if( !fp->lsb ) { step *= elemsize; for( ; slicelen > 0; cur += step, src += elemsize, --slicelen ) memcpy( cur, src, elemsize ); } else if( elemsize == 4 ) { bswap32vec_strided( cur, src, step, slicelen ); } else if( elemsize == 2 ) { bswap16vec_strided( cur, src, step, slicelen ); } return SEGY_OK; } void* tracebuf = rangebuf ? rangebuf : malloc( elems * elemsize ); // like in readsubtr, read a larger chunk and then step through that const int readc = fread( tracebuf, elemsize, elems, fp->fp ); if( readc != elems ) { free( tracebuf ); return SEGY_FREAD_ERROR; } /* rewind, because fread advances the file pointer */ err = fseek( fp->fp, -(elems * elemsize), SEEK_CUR ); if( err != 0 ) { if( !rangebuf ) free( tracebuf ); return SEGY_FSEEK_ERROR; } char* cur = (char*)tracebuf + elemsize * defstart; if( !fp->lsb ) { step *= elemsize; for( ; slicelen > 0; cur += step, --slicelen, src += elemsize ) memcpy( cur, src, elemsize ); } else if( elemsize == 4 ) { bswap32vec_strided( cur, src, step, slicelen ); } else if( elemsize == 2 ) { bswap16vec_strided( cur, src, step, slicelen ); } const int writec = fwrite( tracebuf, elemsize, elems, fp->fp ); if( !rangebuf ) free( tracebuf ); if( writec != elems ) return SEGY_FWRITE_ERROR; return SEGY_OK; } /* * The to/from native functions are aware of the underlying architecture and * the endianness of the input data (through the format enumerator). * * LSB - little endian (least-significant) * MSB - big endian (most-significant) * * For the 4-byte IEEE formats, there are the following scenarios: * * + HOST LSB | HOST MSB * FILE LSB | no-op | bswap * FILE MSB | bswap | no-op * * the ntohs/ntohl functions gracefully handle all FILE MSB, regardless of host * endianness. This does not work when host is MSB, because ntohl would be a * no-op for MSB platforms. Therefore, the final table is: * * + HOST LSB | HOST MSB * FILE LSB | no-op | bswap * FILE MSB | bswap | no-op */ static int segy_native_byteswap( int format, long long size, void* buf ) { const int elemsize = formatsize( format ); if( elemsize == sizeof( uint32_t ) && HOST_LSB ) { bswap32vec( buf, size ); } if( elemsize == sizeof( uint16_t ) && HOST_LSB ) { bswap16vec( buf, size ); } return SEGY_OK; } int segy_to_native( int format, long long size, void* buf ) { const int elemsize = formatsize( format ); if( elemsize < 0 ) return SEGY_INVALID_ARGS; segy_native_byteswap( format, size, buf ); char* dst = (char*)buf; if( format == SEGY_IBM_FLOAT_4_BYTE ) { for( long long i = 0; i < size; ++i ) ibm_native( dst + i * elemsize ); } return SEGY_OK; } int segy_from_native( int format, long long size, void* buf ) { const int elemsize = formatsize( format ); if( elemsize < 0 ) return SEGY_INVALID_ARGS; char* dst = (char*)buf; if( format == SEGY_IBM_FLOAT_4_BYTE ) { for( long long i = 0; i < size; ++i ) native_ibm( dst + i * elemsize ); } return segy_native_byteswap( format, size, buf ); } /* * Determine the position of the element `x` in `xs`. * Returns -1 if the value cannot be found */ static int index_of( int x, const int* xs, int sz ) { for( int i = 0; i < sz; i++ ) { if( xs[i] == x ) return i; } return -1; } /* * Read the inline or crossline `lineno`. If it's an inline or crossline * depends on the parameters. The line has a length of `line_length` traces, * `offsets` are the number of offsets in this file, and `buf` must be of * (minimum) `line_length*samples_per_trace` size. Reads every `stride` trace, * starting at the trace specified by the *position* of the value `lineno` in * `linenos`. If `lineno` isn't present in `linenos`, SEGY_MISSING_LINE_INDEX * will be returned. * * If reading a trace fails, this function will return whatever error * segy_readtrace returns. */ int segy_read_line( segy_file* fp, int line_trace0, int line_length, int stride, int offsets, void* buf, long trace0, int trace_bsize ) { char* dst = (char*) buf; stride *= offsets; for( ; line_length--; line_trace0 += stride, dst += trace_bsize ) { int err = segy_readtrace( fp, line_trace0, dst, trace0, trace_bsize ); if( err != 0 ) return err; } return SEGY_OK; } /* * Write the inline or crossline `lineno`. If it's an inline or crossline * depends on the parameters. The line has a length of `line_length` traces, * and `buf` must be of (minimum) `line_length*samples_per_trace` size. Reads * every `stride` trace, starting at the trace specified by the *position* of * the value `lineno` in `linenos`. If `lineno` isn't present in `linenos`, * SEGY_MISSING_LINE_INDEX will be returned. * * If reading a trace fails, this function will return whatever error * segy_readtrace returns. */ int segy_write_line( segy_file* fp, int line_trace0, int line_length, int stride, int offsets, const void* buf, long trace0, int trace_bsize ) { if( !fp->writable ) return SEGY_READONLY; const char* src = (const char*) buf; stride *= offsets; for( ; line_length--; line_trace0 += stride, src += trace_bsize ) { int err = segy_writetrace( fp, line_trace0, src, trace0, trace_bsize ); if( err != 0 ) return err; } return SEGY_OK; } int segy_line_trace0( int lineno, int line_length, int stride, int offsets, const int* linenos, int linenos_sz, int* traceno ) { int index = index_of( lineno, linenos, linenos_sz ); if( index < 0 ) return SEGY_MISSING_LINE_INDEX; if( stride == 1 ) index *= line_length; *traceno = index * offsets; return SEGY_OK; } int segy_inline_stride( int sorting, int inline_count, int* stride ) { switch( sorting ) { case SEGY_CROSSLINE_SORTING: *stride = inline_count; return SEGY_OK; case SEGY_INLINE_SORTING: *stride = 1; return SEGY_OK; default: return SEGY_INVALID_SORTING; } } int segy_crossline_stride( int sorting, int crossline_count, int* stride ) { switch( sorting ) { case SEGY_CROSSLINE_SORTING: *stride = 1; return SEGY_OK; case SEGY_INLINE_SORTING: *stride = crossline_count; return SEGY_OK; default: return SEGY_INVALID_SORTING; } } int segy_read_textheader( segy_file* fp, char *buf) { return segy_read_ext_textheader(fp, -1, buf ); } int segy_read_ext_textheader( segy_file* fp, int pos, char *buf) { if( pos < -1 ) return SEGY_INVALID_ARGS; if( !fp ) return SEGY_FSEEK_ERROR; const long offset = pos == -1 ? 0 : SEGY_TEXT_HEADER_SIZE + SEGY_BINARY_HEADER_SIZE + (pos * SEGY_TEXT_HEADER_SIZE); #ifdef HAVE_MMAP if ( fp->addr ) { encode( buf, (char*)fp->addr + offset, e2a, SEGY_TEXT_HEADER_SIZE ); buf[ SEGY_TEXT_HEADER_SIZE ] = '\0'; return SEGY_OK; } #endif //HAVE_MMAP int err = fseek( fp->fp, offset, SEEK_SET ); if( err != 0 ) return SEGY_FSEEK_ERROR; char localbuf[ SEGY_TEXT_HEADER_SIZE + 1 ] = { 0 }; const size_t read = fread( localbuf, 1, SEGY_TEXT_HEADER_SIZE, fp->fp ); if( read != SEGY_TEXT_HEADER_SIZE ) return SEGY_FREAD_ERROR; encode( buf, localbuf, e2a, SEGY_TEXT_HEADER_SIZE ); return SEGY_OK; } int segy_write_textheader( segy_file* fp, int pos, const char* buf ) { if( !fp->writable ) return SEGY_READONLY; int err; char mbuf[ SEGY_TEXT_HEADER_SIZE ]; if( pos < 0 ) return SEGY_INVALID_ARGS; err = encode( mbuf, buf, a2e, SEGY_TEXT_HEADER_SIZE ); if( err != 0 ) return err; const long offset = pos == 0 ? 0 : SEGY_TEXT_HEADER_SIZE + SEGY_BINARY_HEADER_SIZE + ((pos-1) * SEGY_TEXT_HEADER_SIZE); #ifdef HAVE_MMAP if( fp->addr ) { return memwrite( fp, (char*)fp->addr + offset, mbuf, SEGY_TEXT_HEADER_SIZE ); } #endif //HAVE_MMAP err = fseek( fp->fp, offset, SEEK_SET ); if( err != 0 ) return SEGY_FSEEK_ERROR; size_t writec = fwrite( mbuf, 1, SEGY_TEXT_HEADER_SIZE, fp->fp ); if( writec != SEGY_TEXT_HEADER_SIZE ) return SEGY_FWRITE_ERROR; return SEGY_OK; } int segy_textheader_size( void ) { return SEGY_TEXT_HEADER_SIZE + 1; } int segy_binheader_size( void ) { return SEGY_BINARY_HEADER_SIZE; } static int scaled_cdp( segy_file* fp, int traceno, float* cdpx, float* cdpy, long trace0, int trace_bsize ) { int32_t x, y, scalar; char trheader[ SEGY_TRACE_HEADER_SIZE ]; int err = segy_traceheader( fp, traceno, trheader, trace0, trace_bsize ); if( err != 0 ) return err; err = segy_get_field( trheader, SEGY_TR_CDP_X, &x ); if( err != 0 ) return err; err = segy_get_field( trheader, SEGY_TR_CDP_Y, &y ); if( err != 0 ) return err; err = segy_get_field( trheader, SEGY_TR_SOURCE_GROUP_SCALAR, &scalar ); if( err != 0 ) return err; float scale = scalar; if( scalar == 0 ) scale = 1.0; if( scalar < 0 ) scale = -1.0 / scale; *cdpx = x * scale; *cdpy = y * scale; return SEGY_OK; } int segy_rotation_cw( segy_file* fp, int line_length, int stride, int offsets, const int* linenos, int linenos_sz, float* rotation, long trace0, int trace_bsize ) { struct coord { float x, y; } nw, sw; int err; int traceno; err = segy_line_trace0( linenos[0], line_length, stride, offsets, linenos, linenos_sz, &traceno ); if( err != 0 ) return err; err = scaled_cdp( fp, traceno, &sw.x, &sw.y, trace0, trace_bsize ); if( err != 0 ) return err; /* read the last trace in the line */ traceno += (line_length - 1) * stride * offsets; err = scaled_cdp( fp, traceno, &nw.x, &nw.y, trace0, trace_bsize ); if( err != 0 ) return err; float x = nw.x - sw.x; float y = nw.y - sw.y; float radians = x || y ? atan2( x, y ) : 0; if( radians < 0 ) radians += 2 * acos(-1); *rotation = radians; return SEGY_OK; } segyio-1.8.3/lib/CMakeLists.txt0000664000372000037200000000737213407674361015756 0ustar travistravisproject(libsegyio C CXX) if(MSVC) set(DLL_EXPORT_FILES src/segy.def) endif() add_library(segyio src/segy.c ${DLL_EXPORT_FILES}) target_link_libraries(segyio ${m} ${ws2}) target_compile_options(segyio BEFORE PRIVATE ${c99} $<$:${warnings-c}> ) target_compile_definitions(segyio PRIVATE ${mmap} ${fstat} ${ftello} $<${HOST_BIG_ENDIAN}:HOST_BIG_ENDIAN> ) set_target_properties(segyio PROPERTIES SOVERSION ${segyio_MAJOR} VERSION ${segyio_MAJOR} ) target_include_directories(segyio PUBLIC $ $ PRIVATE src include ) # # install & export # install(TARGETS segyio EXPORT segyio ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) install(DIRECTORY include/ DESTINATION include) install(EXPORT segyio DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/segyio/cmake FILE segyio-config.cmake ) export(TARGETS segyio FILE segyio-config.cmake) if(EXPERIMENTAL) install(DIRECTORY experimental/ DESTINATION include) endif() if (NOT BUILD_TESTING) return () endif () configure_file(${testdata}/small.sgy test-data/small.sgy COPYONLY) configure_file(${testdata}/small-ps-dec-il-xl-off.sgy test-data/small-ps-dec-il-xl-off.sgy COPYONLY) configure_file(${testdata}/small-ps-dec-il-inc-xl-off.sgy test-data/small-ps-dec-il-inc-xl-off.sgy COPYONLY) configure_file(${testdata}/small-ps-dec-xl-inc-il-off.sgy test-data/small-ps-dec-xl-inc-il-off.sgy COPYONLY) configure_file(${testdata}/small-ps-dec-off-inc-il-xl.sgy test-data/small-ps-dec-off-inc-il-xl.sgy COPYONLY) configure_file(${testdata}/small-ps-dec-il-xl-inc-off.sgy test-data/small-ps-dec-il-xl-inc-off.sgy COPYONLY) configure_file(${testdata}/small-ps-dec-il-off-inc-xl.sgy test-data/small-ps-dec-il-off-inc-xl.sgy COPYONLY) configure_file(${testdata}/small-ps-dec-xl-off-inc-il.sgy test-data/small-ps-dec-xl-off-inc-il.sgy COPYONLY) configure_file(${testdata}/small.sgy test-data/small-w.sgy COPYONLY) configure_file(${testdata}/small-lsb.sgy test-data/small-lsb.sgy COPYONLY) configure_file(${testdata}/1x1.sgy test-data/1x1.sgy COPYONLY) configure_file(${testdata}/1xN.sgy test-data/1xN.sgy COPYONLY) configure_file(${testdata}/f3.sgy test-data/f3.sgy COPYONLY) configure_file(${testdata}/f3-lsb.sgy test-data/f3-lsb.sgy COPYONLY) configure_file(${testdata}/text.sgy test-data/text.sgy COPYONLY) add_executable(c.segy test/testsuite.cpp test/segy.cpp test/segyio-cpp.cpp ) target_include_directories(c.segy PRIVATE src experimental) target_link_libraries(c.segy catch2 segyio) target_compile_options(c.segy BEFORE PRIVATE ${c++11} ${mmap} $<$:${warnings-c}> ) target_compile_definitions(c.segy PRIVATE ${mmap} ) add_test(NAME c.segy COMMAND c.segy) add_test(NAME c.segy.mmap COMMAND c.segy --test-mmap) add_test(NAME c.segy.lsb COMMAND c.segy --test-lsb) add_test(NAME c.segy.mmap.lsb COMMAND c.segy --test-mmap --test-lsb) add_test(NAME cpp.segy COMMAND c.segy [c++]) segyio-1.8.3/lib/test/0000775000372000037200000000000013407674361014164 5ustar travistravissegyio-1.8.3/lib/test/matchers.hpp0000664000372000037200000000157213407674361016510 0ustar travistravis#ifndef SEGYIO_MATCHERS_HPP #define SEGYIO_MATCHERS_HPP #include #include #include namespace { class ApproxRange : public Catch::MatcherBase< std::vector< float > > { public: explicit ApproxRange( const std::vector< float >& xs ) : lhs( xs ) {} virtual bool match( const std::vector< float >& xs ) const override { if( xs.size() != lhs.size() ) return false; for( std::size_t i = 0; i < xs.size(); ++i ) if( xs[ i ] != Approx(this->lhs[ i ]) ) return false; return true; } virtual std::string describe() const override { using str = Catch::StringMaker< std::vector< float > >; return "~= " + str::convert( this->lhs ); } private: std::vector< float > lhs; }; } #endif // SEGYIO_MATCHERS_HPP segyio-1.8.3/lib/test/testsuite.cpp0000664000372000037200000000247413407674361016730 0ustar travistravis#define CATCH_CONFIG_RUNNER #include #include #include "test-config.hpp" const char* testcfg::apply( const char* path ) { if( !this->lsbit ) return path; std::string p( path ); if( p == "test-data/small.sgy" ) return "test-data/small-lsb.sgy"; if( p == "test-data/f3.sgy" ) return "test-data/f3-lsb.sgy"; return path; } void testcfg::mmap( segy_file* fp ) { if( this->memmap ) { #ifdef HAVE_MMAP REQUIRE( segy_mmap( fp ) == SEGY_OK ); #endif //HAVE_MMAP } } void testcfg::lsb( segy_file* fp ) { if( this->lsbit ) { REQUIRE( segy_set_format( fp, SEGY_LSB ) == SEGY_OK ); } } void testcfg::apply( segy_file* fp ) { this->mmap( fp ); this->lsb( fp ); } testcfg& testcfg::config() { static testcfg s; return s; } int main( int argc, char** argv ) { Catch::Session session; auto& cfg = testcfg::config(); using namespace Catch::clara; auto cli = session.cli() | Opt( cfg.memmap ) ["--test-mmap"] ("run with memory mapped files") | Opt( cfg.lsbit ) ["--test-lsb"] ("run with LSB files") ; session.cli( cli ); const int errc = session.applyCommandLine( argc, argv ); if( errc ) return errc; return session.run(); } segyio-1.8.3/lib/test/test-config.hpp0000664000372000037200000000130613407674361017117 0ustar travistravis#ifndef SEGYIO_TEST_CONFIG_HPP #define SEGYIO_TEST_CONFIG_HPP #include struct testcfg { /* * If one of the supported files, get -lsb version of file path */ const char* apply( const char* ); /* * call testcfg::config().apply(fp) to enable both mmap and lsb * configurations for this test. * * If only one of those are supported/useful/sensical (e.g. there is no * -lsb file), call the feature directly testcfg::config().mmap( fp ); */ void mmap( segy_file* ); void lsb( segy_file* ); void apply( segy_file* ); static testcfg& config(); bool memmap = false; bool lsbit = false; }; #endif // SEGYIO_TEST_CONFIG_HPP segyio-1.8.3/lib/test/segy.cpp0000664000372000037200000015077213407674361015653 0ustar travistravis#include #include #include #include #include #include #include #include "matchers.hpp" #include #include #include "test-config.hpp" namespace { struct segy_fclose { void operator()( segy_file* fp ) { if( fp ) segy_close( fp ); } }; using unique_segy = std::unique_ptr< segy_file, segy_fclose >; segy_file* openfile( const std::string& path, const std::string& mode ) { const auto* p = testcfg::config().apply( path.c_str() ); unique_segy ptr( segy_open( p, mode.c_str() ) ); REQUIRE( ptr ); testcfg::config().apply( ptr.get() ); return ptr.release(); } const std::string& copyfile( const std::string& src, const std::string& dst ) { std::ifstream in( src, std::ios::binary ); std::ofstream out( dst, std::ios::binary ); out << in.rdbuf(); return dst; } struct slice { int start, stop, step; }; std::string str( const slice& s ) { return "(" + std::to_string( s.start ) + "," + std::to_string( s.stop ) + "," + std::to_string( s.step ) + ")"; } struct Err { // cppcheck-suppress noExplicitConstructor Err( int err ) : err( err ) {} bool operator == ( Err other ) const { return this->err == other.err; } bool operator != ( Err other ) const { return !(*this == other); } static Err ok() { return SEGY_OK; } static Err args() { return SEGY_INVALID_ARGS; } static Err field() { return SEGY_INVALID_FIELD; } int err; }; } namespace Catch { template<> struct StringMaker< Err > { static std::string convert( const Err& err ) { switch( err.err ) { case SEGY_OK : return "OK"; case SEGY_FOPEN_ERROR: return "SEGY_FOPEN_ERROR"; case SEGY_FSEEK_ERROR: return "SEGY_FSEEK_ERROR"; case SEGY_FREAD_ERROR: return "SEGY_FREAD_ERROR"; case SEGY_FWRITE_ERROR: return "SEGY_FWRITE_ERROR"; case SEGY_INVALID_FIELD: return "SEGY_INVALID_FIELD"; case SEGY_INVALID_SORTING: return "SEGY_INVALID_SORTING"; case SEGY_MISSING_LINE_INDEX: return "SEGY_MISSING_LINE_INDEX"; case SEGY_INVALID_OFFSETS: return "SEGY_INVALID_OFFSETS"; case SEGY_TRACE_SIZE_MISMATCH: return "SEGY_TRACE_SIZE_MISMATCH"; case SEGY_INVALID_ARGS: return "SEGY_INVALID_ARGS"; case SEGY_MMAP_ERROR: return "SEGY_MMAP_ERROR"; case SEGY_MMAP_INVALID: return "SEGY_MMAP_INVALID"; } return "Unknown error"; } }; } namespace { void regular_geometry( segy_file* fp, int traces, long trace0, int trace_bsize, int expected_ilines, int expected_xlines, int expected_offset) { /* A simple "no-surprises" type of file, that's inline sorted, post-stack * (1 offset only), no weird header field positions, meaning the test would * be pure repetition for common files */ const int il = SEGY_TR_INLINE; const int xl = SEGY_TR_CROSSLINE; const int of = SEGY_TR_OFFSET; const int sorting = SEGY_INLINE_SORTING; GIVEN( "a post stack file" ) { int offsets = -1; const Err err = segy_offsets( fp, il, xl, traces, &offsets, trace0, trace_bsize ); THEN( "there is only one offset" ) { CHECK( err == Err::ok() ); CHECK( offsets == 1 ); } WHEN( "swapping inline and crossline position" ) { offsets = -1; const Err erc = segy_offsets( fp, xl, il, traces, &offsets, trace0, trace_bsize ); THEN( "there is only one offset" ) { CHECK( erc == Err::ok() ); CHECK( offsets == 1 ); } } } const int offsets = 1; WHEN( "determining offset labels" ) { int offset_index = -1; const Err err = segy_offset_indices( fp, of, offsets, &offset_index, trace0, trace_bsize ); CHECK( err == Err::ok() ); CHECK( offset_index == expected_offset ); } WHEN( "counting lines" ) { int ilsz = -1; int xlsz = -1; WHEN( "using segy_count_lines" ) { const Err err = segy_count_lines( fp, xl, offsets, &ilsz, &xlsz, trace0, trace_bsize ); CHECK( err == Err::ok() ); CHECK( ilsz == expected_ilines ); CHECK( xlsz == expected_xlines ); } WHEN( "using segy_lines_count" ) { const Err err = segy_lines_count( fp, il, xl, sorting, offsets, &ilsz, &xlsz, trace0, trace_bsize ); CHECK( err == Err::ok() ); CHECK( ilsz == expected_ilines ); CHECK( xlsz == expected_xlines ); } } } bool success( Err err ) { return err == Err::ok(); } struct smallfix { segy_file* fp = nullptr; smallfix() { fp = openfile( "test-data/small.sgy", "rb" ); } smallfix( const smallfix& ) = delete; smallfix& operator=( const smallfix& ) = delete; ~smallfix() { segy_fclose()( fp ); } }; struct smallbin : smallfix { char bin[ SEGY_BINARY_HEADER_SIZE ]; smallbin() : smallfix() { REQUIRE( Err( segy_binheader( fp, bin ) ) == Err::ok() ); } }; struct smallbasic : smallfix { long trace0 = 3600; int trace_bsize = 50 * 4; int samples = 50; }; struct smallheader : smallbasic { char header[ SEGY_TRACE_HEADER_SIZE ]; smallheader() : smallbasic() { Err err = segy_traceheader( fp, 0, header, trace0, trace_bsize ); REQUIRE( success( err ) ); } }; struct smallfields : smallbasic { int il = SEGY_TR_INLINE; int xl = SEGY_TR_CROSSLINE; int of = SEGY_TR_OFFSET; }; struct smallstep : smallbasic { int traceno = 10; int format = SEGY_IBM_FLOAT_4_BYTE; }; struct smallsize : smallfields { int traces = 25; }; struct smallshape : smallsize { int offsets = 1; int ilines = 5; int xlines = 5; int sorting = SEGY_INLINE_SORTING; }; struct smallcube : smallshape { int stride = 1; std::vector< int > inlines = { 1, 2, 3, 4, 5 }; std::vector< int > crosslines = { 20, 21, 22, 23, 24 }; int format = SEGY_IBM_FLOAT_4_BYTE; }; int arbitrary_int() { /* * in order to verify that functions don't modify their output arguments if * the function fail, it has to be compared to an arbitrary value that * should be equal before and after. It has to be initialised, but the * value itself is of no significance. */ return -1; } } TEST_CASE_METHOD( smallbin, "samples+positions from binary header are correct", "[c.segy]" ) { int samples = segy_samples( bin ); long trace0 = segy_trace0( bin ); int trace_bsize = segy_trsize( SEGY_IBM_FLOAT_4_BYTE, samples ); CHECK( trace0 == 3600 ); CHECK( samples == 50 ); CHECK( trace_bsize == 50 * 4 ); } TEST_CASE_METHOD( smallfix, "sample format can be overriden", "[c.segy]" ) { Err err = segy_set_format( fp, SEGY_IEEE_FLOAT_4_BYTE ); CHECK( err == Err::ok() ); } TEST_CASE_METHOD( smallfix, "sample format fails on invalid format", "[c.segy]" ) { Err err = segy_set_format( fp, 10 ); CHECK( err == Err::args() ); } TEST_CASE_METHOD( smallbasic, "trace count is 25", "[c.segy]" ) { int traces; Err err = segy_traces( fp, &traces, trace0, trace_bsize ); CHECK( success( err ) ); CHECK( traces == 25 ); } TEST_CASE_METHOD( smallbasic, "trace0 beyond EOF is an argument error", "[c.segy]" ) { const int input_traces = arbitrary_int(); int traces = input_traces; Err err = segy_traces( fp, &traces, 50000, trace_bsize ); CHECK( err == Err::args() ); CHECK( traces == input_traces ); } TEST_CASE_METHOD( smallbasic, "negative trace0 is an argument error", "[c.segy]" ) { const int input_traces = arbitrary_int(); int traces = input_traces; Err err = segy_traces( fp, &traces, -1, trace_bsize ); CHECK( err == Err::args() ); CHECK( traces == input_traces ); } TEST_CASE_METHOD( smallbasic, "erroneous trace_bsize is detected", "[c.segy]" ) { const int input_traces = arbitrary_int(); int traces = input_traces; const int too_long_bsize = trace_bsize + sizeof( float ); Err err = segy_traces( fp, &traces, trace0, too_long_bsize ); CHECK( err == SEGY_TRACE_SIZE_MISMATCH ); CHECK( traces == input_traces ); } TEST_CASE_METHOD( smallheader, "valid trace-header fields can be read", "[c.segy]" ) { int32_t ilno; Err err = segy_get_field( header, SEGY_TR_INLINE, &ilno ); CHECK( success( err ) ); CHECK( ilno == 1 ); } TEST_CASE_METHOD( smallheader, "zero header field is an argument error", "[c.segy]" ) { const int32_t input_value = arbitrary_int(); auto value = input_value; Err err = segy_get_field( header, 0, &value ); CHECK( err == Err::field() ); CHECK( value == input_value ); } TEST_CASE_METHOD( smallheader, "negative header field is an argument error", "[c.segy]" ) { const int32_t input_value = arbitrary_int(); auto value = input_value; Err err = segy_get_field( header, -1, &value ); CHECK( err == Err::field() ); CHECK( value == input_value ); } TEST_CASE_METHOD( smallheader, "unaligned header field is an argument error", "[c.segy]" ) { const int32_t input_value = arbitrary_int(); auto value = input_value; Err err = segy_get_field( header, SEGY_TR_INLINE + 1, &value ); CHECK( err == Err::field() ); CHECK( value == input_value ); } TEST_CASE_METHOD( smallheader, "too large header field is an argument error", "[c.segy]" ) { const int32_t input_value = arbitrary_int(); auto value = input_value; Err err = segy_get_field( header, SEGY_TRACE_HEADER_SIZE + 10, &value ); CHECK( err == Err::field() ); CHECK( value == input_value ); } TEST_CASE_METHOD( smallfields, "inline sorting is detected", "[c.segy]" ) { int sorting; Err err = segy_sorting( fp, il, xl, of, &sorting, trace0, trace_bsize ); CHECK( success( err ) ); CHECK( sorting == SEGY_INLINE_SORTING ); } TEST_CASE_METHOD( smallfields, "crossline sorting is detected with swapped il/xl", "[c.segy]" ) { int sorting; Err err = segy_sorting( fp, xl, il, of, &sorting, trace0, trace_bsize ); CHECK( success( err ) ); CHECK( sorting == SEGY_CROSSLINE_SORTING ); } TEST_CASE_METHOD( smallfields, "invalid in-between byte offsets are detected", "[c.segy]" ) { int sorting; Err err = segy_sorting( fp, il + 1, xl, of, &sorting, trace0, trace_bsize ); CHECK( err == SEGY_INVALID_FIELD ); err = segy_sorting( fp, il, xl + 1, of, &sorting, trace0, trace_bsize ); CHECK( err == SEGY_INVALID_FIELD ); err = segy_sorting( fp, il, xl, of + 1, &sorting, trace0, trace_bsize ); CHECK( err == SEGY_INVALID_FIELD ); } TEST_CASE_METHOD( smallsize, "post-stack file offset-count is 1", "[c.segy]" ) { int offsets; Err err = segy_offsets( fp, il, xl, traces, &offsets, trace0, trace_bsize ); CHECK( success( err ) ); CHECK( offsets == 1 ); } TEST_CASE_METHOD( smallsize, "swapped il/xl post-stack file offset-count is 1", "[c.segy]" ) { int offsets; Err err = segy_offsets( fp, xl, il, traces, &offsets, trace0, trace_bsize ); CHECK( success( err ) ); CHECK( offsets == 1 ); } TEST_CASE_METHOD( smallshape, "correct # of lines are detected", "[c.segy]" ) { int expected_ils = 5; int expected_xls = 5; int count_inlines; int count_crosslines; Err err_count = segy_count_lines( fp, xl, offsets, &count_inlines, &count_crosslines, trace0, trace_bsize ); int lines_inlines; int lines_crosslines; Err err_lines = segy_lines_count( fp, il, xl, sorting, offsets, &lines_inlines, &lines_crosslines, trace0, trace_bsize ); CHECK( success( err_count ) ); CHECK( success( err_lines ) ); CHECK( count_inlines == expected_ils ); CHECK( count_crosslines == expected_xls ); CHECK( lines_inlines == expected_ils ); CHECK( lines_crosslines == expected_xls ); CHECK( lines_inlines == count_inlines ); CHECK( lines_crosslines == count_crosslines ); } TEST_CASE_METHOD( smallshape, "line lengths are correct", "[c.segy]" ) { CHECK( segy_inline_length( xlines ) == ilines ); CHECK( segy_inline_length( ilines ) == xlines ); } TEST_CASE_METHOD( smallshape, "correct offset labels are detected", "[c.segy]" ) { const std::vector< int > expected = { 1 }; std::vector< int > labels( 1 ); Err err = segy_offset_indices( fp, of, offsets, labels.data(), trace0, trace_bsize ); CHECK( success( err ) ); CHECK_THAT( labels, Catch::Equals( expected ) ); } TEST_CASE_METHOD( smallshape, "correct inline labels are detected", "[c.segy]" ) { const std::vector< int > expected = { 1, 2, 3, 4, 5 }; std::vector< int > labels( 5 ); Err err = segy_inline_indices( fp, il, sorting, ilines, xlines, offsets, labels.data(), trace0, trace_bsize ); CHECK( success( err ) ); CHECK_THAT( labels, Catch::Equals( expected ) ); } TEST_CASE_METHOD( smallshape, "correct crossline labels are detected", "[c.segy]" ) { const std::vector< int > expected = { 20, 21, 22, 23, 24 }; std::vector< int > labels( 5 ); Err err = segy_crossline_indices( fp, xl, sorting, ilines, xlines, offsets, labels.data(), trace0, trace_bsize ); CHECK( success( err ) ); CHECK_THAT( labels, Catch::Equals( expected ) ); } TEST_CASE_METHOD( smallshape, "correct inline stride is detected", "[c.segy]" ) { int stride; Err err = segy_inline_stride( sorting, ilines, &stride ); CHECK( success( err ) ); CHECK( stride == 1 ); } TEST_CASE_METHOD( smallshape, "correct inline stride with swapped sorting", "[c.segy]" ) { int stride; Err err = segy_inline_stride( SEGY_CROSSLINE_SORTING, ilines, &stride ); CHECK( success( err ) ); CHECK( stride == ilines ); } TEST_CASE_METHOD( smallcube, "correct first trace is detected for an inline", "[c.segy]" ) { const int label = inlines.at( 3 ); int line_trace0; Err err = segy_line_trace0( label, xlines, stride, offsets, inlines.data(), inlines.size(), &line_trace0 ); CHECK( success( err ) ); CHECK( line_trace0 == 15 ); } TEST_CASE_METHOD( smallcube, "missing inline-label is detected and reported", "[c.segy]" ) { const int label = inlines.back() + 1; int line_trace0; Err err = segy_line_trace0( label, xlines, stride, offsets, inlines.data(), inlines.size(), &line_trace0 ); CHECK( err == SEGY_MISSING_LINE_INDEX ); } TEST_CASE_METHOD( smallshape, "correct crossline stride is detected", "[c.segy]" ) { int stride; Err err = segy_crossline_stride( sorting, xlines, &stride ); CHECK( success( err ) ); CHECK( stride == ilines ); } TEST_CASE_METHOD( smallshape, "correct crossline stride with swapped sorting", "[c.segy]" ) { int stride; Err err = segy_crossline_stride( SEGY_CROSSLINE_SORTING, xlines, &stride ); CHECK( success( err ) ); CHECK( stride == 1 ); } TEST_CASE_METHOD( smallcube, "correct first trace is detected for a crossline", "[c.segy]" ) { const int label = crosslines.at( 2 ); const int stride = ilines; int line_trace0; Err err = segy_line_trace0( label, ilines, stride, offsets, crosslines.data(), crosslines.size(), &line_trace0 ); CHECK( success( err ) ); CHECK( line_trace0 == 2 ); } TEST_CASE_METHOD( smallcube, "missing crossline-label is detected and reported", "[c.segy]" ) { const int label = crosslines.back() + 1; const int stride = ilines; int line_trace0; Err err = segy_line_trace0( label, ilines, stride, offsets, inlines.data(), inlines.size(), &line_trace0 ); CHECK( err == SEGY_MISSING_LINE_INDEX ); } TEST_CASE_METHOD( smallstep, "read ascending strided subtrace", "[c.segy]" ) { const int start = 3; const int stop = 19; const int step = 5; void* rangebuf = nullptr; const std::vector< float > expected = { 3.20003f, 3.20008f, 3.20013f, 3.20018f }; std::vector< float > xs( expected.size() ); Err err = segy_readsubtr( fp, traceno, start, stop, step, xs.data(), rangebuf, trace0, trace_bsize ); segy_to_native( format, xs.size(), xs.data() ); CHECK( success( err ) ); CHECK_THAT( xs, ApproxRange( expected ) ); } TEST_CASE_METHOD( smallstep, "read descending strided subtrace", "[c.segy]" ) { const int start = 18; const int stop = 2; const int step = -5; void* rangebuf = nullptr; const std::vector< float > expected = { 3.20018f, 3.20013f, 3.20008f, 3.20003f }; std::vector< float > xs( expected.size() ); Err err = segy_readsubtr( fp, traceno, start, stop, step, xs.data(), rangebuf, trace0, trace_bsize ); segy_to_native( format, xs.size(), xs.data() ); CHECK( success( err ) ); CHECK_THAT( xs, ApproxRange( expected ) ); } TEST_CASE_METHOD( smallstep, "read descending contiguous subtrace", "[c.segy]" ) { const int start = 3; const int stop = -1; const int step = -1; void* rangebuf = nullptr; const std::vector< float > expected = { 3.20003f, 3.20002f, 3.20001f, 3.20000f }; std::vector< float > xs( expected.size() ); Err err = segy_readsubtr( fp, traceno, start, stop, step, xs.data(), rangebuf, trace0, trace_bsize ); segy_to_native( format, xs.size(), xs.data() ); CHECK( success( err ) ); CHECK_THAT( xs, ApproxRange( expected ) ); } TEST_CASE_METHOD( smallstep, "read descending strided subtrace with pre-start", "[c.segy]" ) { const int start = 24; const int stop = -1; const int step = -5; const std::vector< float > expected = { 3.20024f, 3.20019f, 3.20014f, 3.20009f, 3.20004f }; std::vector< float > xs( expected.size() ); Err err = segy_readsubtr( fp, traceno, start, stop, step, xs.data(), nullptr, trace0, trace_bsize ); segy_to_native( format, xs.size(), xs.data() ); CHECK( success( err ) ); CHECK_THAT( xs, ApproxRange( expected ) ); } TEST_CASE_METHOD( smallcube, "reading the first inline gives correct values", "[c.segy]" ) { // first line starts at first trace const int line_trace0 = 0; const std::vector< float > expected = [=] { std::vector< float > xs( samples * xlines ); for( int i = 0; i < xlines; ++i ) { Err err = segy_readtrace( fp, i, xs.data() + (i * samples), trace0, trace_bsize ); REQUIRE( success( err ) ); } segy_to_native( format, xs.size(), xs.data() ); return xs; }(); std::vector< float > line( expected.size() ); Err err = segy_read_line( fp, line_trace0, crosslines.size(), stride, offsets, line.data(), trace0, trace_bsize ); segy_to_native( format, line.size(), line.data() ); CHECK( success( err ) ); CHECK_THAT( line, ApproxRange( expected ) ); } TEST_CASE_METHOD( smallcube, "reading the first crossline gives correct values", "[c.segy]" ) { // first line starts at first trace const int line_trace0 = 0; const int stride = ilines; const std::vector< float > expected = [=] { std::vector< float > xs( samples * ilines ); for( int i = 0; i < ilines; ++i ) { Err err = segy_readtrace( fp, i * stride, xs.data() + (i * samples), trace0, trace_bsize ); REQUIRE( success( err ) ); } segy_to_native( format, xs.size(), xs.data() ); return xs; }(); std::vector< float > line( expected.size() ); Err err = segy_read_line( fp, line_trace0, inlines.size(), stride, offsets, line.data(), trace0, trace_bsize ); segy_to_native( format, line.size(), line.data() ); CHECK( success( err ) ); CHECK_THAT( line, ApproxRange( expected ) ); } template< int Start, int Stop, int Step > struct writesubtr { segy_file* fp = nullptr; int start = Start; int stop = Stop; int step = Step; int traceno = 5; int trace0 = 3600; int trace_bsize = 50 * 4; int format = SEGY_IBM_FLOAT_4_BYTE; void* rangebuf = nullptr; std::vector< float > trace; std::vector< float > expected; writesubtr() { std::string name = std::string("write-sub-trace ") + "[" + std::to_string( start ) + "," + std::to_string( stop ) + "," + std::to_string( step ) + std::string(testcfg::config().memmap ? "-mmap" : "") + std::string(testcfg::config().lsbit ? "-lsb" : "") + "].sgy"; copyfile( "test-data/small.sgy", name ); fp = openfile( name, "r+b" ); trace.assign( 50, 0 ); expected.resize( trace.size() ); Err err = segy_writetrace( fp, traceno, trace.data(), trace0, trace_bsize ); REQUIRE( success( err ) ); } ~writesubtr() { REQUIRE( fp ); /* test that writes are observable */ trace.assign( trace.size(), 0 ); Err err = segy_readtrace( fp, traceno, trace.data(), trace0, trace_bsize ); CHECK( success( err ) ); segy_to_native( format, trace.size(), trace.data() ); CHECK_THAT( trace, ApproxRange( expected ) ); segy_close( fp ); } writesubtr( const writesubtr& ) = delete; writesubtr& operator=( const writesubtr& ) = delete; }; TEST_CASE_METHOD( (writesubtr< 3, 19, 5 >), "write ascending strided subtrace", "[c.segy]" ) { std::vector< float > out = { 3, 8, 13, 18 }; expected.at( 3 ) = out.at( 0 ); expected.at( 8 ) = out.at( 1 ); expected.at( 13 ) = out.at( 2 ); expected.at( 18 ) = out.at( 3 ); segy_from_native( format, out.size(), out.data() ); Err err = segy_writesubtr( fp, traceno, start, stop, step, out.data(), rangebuf, trace0, trace_bsize ); CHECK( success( err ) ); } TEST_CASE_METHOD( (writesubtr< 18, 2, -5 >), "write descending strided subtrace", "[c.segy]" ) { std::vector< float > out = { 18, 13, 8, 3 }; expected.at( 18 ) = out.at( 0 ); expected.at( 13 ) = out.at( 1 ); expected.at( 8 ) = out.at( 2 ); expected.at( 3 ) = out.at( 3 ); segy_from_native( format, out.size(), out.data() ); Err err = segy_writesubtr( fp, traceno, start, stop, step, out.data(), rangebuf, trace0, trace_bsize ); CHECK( success( err ) ); } TEST_CASE_METHOD( (writesubtr< 24, -1, -5 >), "write descending strided subtrace with pre-start", "[c.segy]" ) { std::vector< float > out = { 24, 19, 14, 9, 4 }; expected.at( 24 ) = out.at( 0 ); expected.at( 19 ) = out.at( 1 ); expected.at( 14 ) = out.at( 2 ); expected.at( 9 ) = out.at( 3 ); expected.at( 4 ) = out.at( 4 ); segy_from_native( format, out.size(), out.data() ); Err err = segy_writesubtr( fp, traceno, start, stop, step, out.data(), rangebuf, trace0, trace_bsize ); CHECK( success( err ) ); } TEST_CASE_METHOD( smallfields, "reading inline label from every trace header", "[c.segy]" ) { const std::vector< int > inlines = { 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, }; const int start = 0, stop = 25, step = 1; std::vector< int > out( inlines.size() ); const Err err = segy_field_forall( fp, il, start, stop, step, out.data(), trace0, trace_bsize ); CHECK( success( err ) ); CHECK_THAT( out, Catch::Equals( inlines ) ); } TEST_CASE_METHOD( smallfields, "reading crossline label from every trace header", "[c.segy]" ) { const std::vector< int > crosslines = { 20, 21, 22, 23, 24, 20, 21, 22, 23, 24, 20, 21, 22, 23, 24, 20, 21, 22, 23, 24, 20, 21, 22, 23, 24, }; const int start = 0, stop = 25, step = 1; std::vector< int > out( crosslines.size() ); const Err err = segy_field_forall( fp, xl, start, stop, step, out.data(), trace0, trace_bsize ); CHECK( success( err ) ); CHECK_THAT( out, Catch::Equals( crosslines ) ); } TEST_CASE_METHOD( smallfields, "reading every 3rd crossline label", "[c.segy]" ) { const std::vector< int > crosslines = { 21, 24, 22, 20, 23, 21, 24, 22, }; const int start = 1, stop = 25, step = 3; std::vector< int > out( crosslines.size() ); const Err err = segy_field_forall( fp, xl, start, stop, step, out.data(), trace0, trace_bsize ); CHECK( success( err ) ); CHECK_THAT( out, Catch::Equals( crosslines ) ); } TEST_CASE_METHOD( smallfields, "reverse-reading every 3rd crossline label", "[c.segy]" ) { const std::vector< int > crosslines = { 22, 24, 21, 23, 20, 22, 24, 21 }; const int start = 22, stop = 0, step = -3; std::vector< int > out( crosslines.size() ); const Err err = segy_field_forall( fp, xl, start, stop, step, out.data(), trace0, trace_bsize ); CHECK( success( err ) ); CHECK_THAT( out, Catch::Equals( crosslines ) ); } TEST_CASE_METHOD( smallfields, "reverse-reading every 5th crossline label", "[c.segy]" ) { const std::vector< int > crosslines = { 24, 24, 24, 24, 24 }; const int start = 24, stop = -1, step = -5; std::vector< int > out( crosslines.size() ); const Err err = segy_field_forall( fp, xl, start, stop, step, out.data(), trace0, trace_bsize ); CHECK( success( err ) ); CHECK_THAT( out, Catch::Equals( crosslines ) ); } TEST_CASE( "setting unaligned header-field fails", "[c.segy]" ) { char header[ SEGY_TRACE_HEADER_SIZE ]; const int32_t v = arbitrary_int(); Err err = segy_set_field( header, SEGY_TR_INLINE + 1, v ); CHECK( err == Err::field() ); } TEST_CASE( "setting negative header-field fails", "[c.segy]" ) { char header[ SEGY_TRACE_HEADER_SIZE ]; const int32_t v = arbitrary_int(); Err err = segy_set_field( header, -1, v ); CHECK( err == Err::field() ); } TEST_CASE( "setting too large header-field fails", "[c.segy]" ) { char header[ SEGY_TRACE_HEADER_SIZE ]; const int32_t v = arbitrary_int(); Err err = segy_set_field( header, SEGY_TRACE_HEADER_SIZE + 10, v ); CHECK( err == Err::field() ); } TEST_CASE( "setting correct header fields succeeds", "[c.segy]" ) { char header[ SEGY_TRACE_HEADER_SIZE ]; const int32_t input = 1; const int field = SEGY_TR_INLINE; Err err = segy_set_field( header, field, input ); CHECK( success( err ) ); int32_t output; err = segy_get_field( header, field, &output ); CHECK( success( err ) ); CHECK( output == input ); } SCENARIO( "modifying trace header", "[c.segy]" ) { const int samples = 10; int trace_bsize = segy_trsize( SEGY_IBM_FLOAT_4_BYTE, samples ); const int trace0 = 0; const float emptytr[ samples ] = {}; const char emptyhdr[ SEGY_TRACE_HEADER_SIZE ] = {}; WHEN( "writing iline no" ) { char header[ SEGY_TRACE_HEADER_SIZE ] = {}; Err err = segy_set_field( header, SEGY_TR_INLINE, 2 ); CHECK( err == Err::ok() ); err = segy_set_field( header, SEGY_TR_SOURCE_GROUP_SCALAR, -100 ); CHECK( err == Err::ok() ); THEN( "the header buffer is updated") { int ilno = 0; int scale = 0; err = segy_get_field( header, SEGY_TR_INLINE, &ilno ); CHECK( err == Err::ok() ); err = segy_get_field( header, SEGY_TR_SOURCE_GROUP_SCALAR, &scale ); CHECK( err == Err::ok() ); CHECK( ilno == 2 ); CHECK( scale == -100 ); } const char* file = "write-traceheader.sgy"; unique_segy ufp( segy_open( file, "w+b" ) ); auto fp = ufp.get(); /* make a file and write to last trace (to accurately get size) */ err = segy_write_traceheader( fp, 10, emptyhdr, trace0, trace_bsize ); REQUIRE( err == Err::ok() ); err = segy_writetrace( fp, 10, emptytr, trace0, trace_bsize ); REQUIRE( err == Err::ok() ); /* memory map only after writing last trace, so size is correct */ testcfg::config().mmap( fp ); err = segy_write_traceheader( fp, 5, header, trace0, trace_bsize ); CHECK( err == Err::ok() ); THEN( "changes are observable on disk" ) { char fresh[ SEGY_TRACE_HEADER_SIZE ] = {}; int ilno = 0; int scale = 0; err = segy_traceheader( fp, 5, fresh, trace0, trace_bsize ); CHECK( err == Err::ok() ); err = segy_get_field( fresh, SEGY_TR_INLINE, &ilno ); CHECK( err == Err::ok() ); err = segy_get_field( fresh, SEGY_TR_SOURCE_GROUP_SCALAR, &scale ); CHECK( err == Err::ok() ); CHECK( ilno == 2 ); CHECK( scale == -100 ); } } } namespace { int check_sorting( const std::string& name ) { int trace0 = 3600; int trace_bsize = 10 * 4; int sorting; unique_segy ufp( segy_open( name.c_str(), "rb" ) ); auto fp = ufp.get(); Err err = segy_sorting( fp, SEGY_TR_INLINE, SEGY_TR_CROSSLINE, SEGY_TR_OFFSET, &sorting, trace0, trace_bsize ); CHECK( success( err ) ); return sorting; } } TEST_CASE("is sorted when (il, xl, offset) decreases", "[c.segy]") { auto sorting = check_sorting( "test-data/small-ps-dec-il-xl-off.sgy" ); CHECK( sorting == SEGY_INLINE_SORTING ); } TEST_CASE("is sorted when offset increases, (il, xl) decreases", "[c.segy]") { auto sorting = check_sorting( "test-data/small-ps-dec-il-inc-xl-off.sgy" ); CHECK( sorting == SEGY_INLINE_SORTING ); } TEST_CASE("is sorted when (il, offset) increases, xl decreases", "[c.segy]") { auto sorting = check_sorting( "test-data/small-ps-dec-xl-inc-il-off.sgy" ); CHECK( sorting == SEGY_INLINE_SORTING ); } TEST_CASE("is sorted when (il, xl) increases, offset decreases", "[c.segy]") { auto sorting = check_sorting( "test-data/small-ps-dec-off-inc-il-xl.sgy" ); CHECK( sorting == SEGY_INLINE_SORTING ); } TEST_CASE("is sorted when (il, xl, offset) increases", "[c.segy]") { auto sorting = check_sorting( "test-data/small-ps-dec-il-xl-inc-off.sgy" ); CHECK( sorting == SEGY_INLINE_SORTING ); } TEST_CASE("is sorted when offset increases, (il, xl) decreases (post-stack)", "[c.segy]") { auto sorting = check_sorting( "test-data/small-ps-dec-il-off-inc-xl.sgy" ); CHECK( sorting == SEGY_INLINE_SORTING ); } TEST_CASE("is sorted when il increases, (xl, offset) decreases", "[c.segy]") { auto sorting = check_sorting( "test-data/small-ps-dec-xl-off-inc-il.sgy" ); CHECK( sorting == SEGY_INLINE_SORTING ); } SCENARIO( "reading text header", "[c.segy]" ) { const std::string expected = "C 1 DATE: 22/02/2016 " "C 2 AN INCREASE IN AMPLITUDE EQUALS AN INCREASE IN ACOUSTIC IMPEDANCE " "C 3 FIRST SAMPLE: 4 MS, LAST SAMPLE: 1400 MS, SAMPLE INTERVAL: 4 MS " "C 4 DATA RANGE: INLINES=(2479-2500) (INC 1),CROSSLINES=(1428-1440) (INC 1) " "C 5 PROCESSING GRID CORNERS: " "C 6 DISTANCE BETWEEN INLINES: 2499.75 M, CROSSLINES: 1250 M " "C 7 1: INLINE 2479, CROSSLINE 1428, UTM-X 9976386.00, UTM-Y 9989096.00 " "C 8 2: INLINE 2479, CROSSLINE 1440, UTM-X 9983886.00, UTM-Y 10002087.00 " "C 9 3: INLINE 2500, CROSSLINE 1428, UTM-X 10021847.00, UTM-Y 9962849.00 " "C10 4: INLINE 2500, CROSSLINE 1440, UTM-X 10029348.00, UTM-Y 9975839.00 " "C11 TRACE HEADER POSITION: " "C12 INLINE BYTES 005-008 | OFFSET BYTES 037-040 " "C13 CROSSLINE BYTES 021-024 | CMP UTM-X BYTES 181-184 " "C14 CMP UTM-Y BYTES 185-188 " "C15 END EBCDIC HEADER " "C16 " "C17 " "C18 " "C19 " "C20 " "C21 " "C22 " "C23 " "C24 " "C25 " "C26 " "C27 " "C28 " "C29 " "C30 " "C31 " "C32 " "C33 " "C34 " "C35 " "C36 " "C37 " "C38 " "C39 " "C40 \x80"; const char* file = "test-data/text.sgy"; unique_segy ufp{ openfile( file, "rb" ) }; auto fp = ufp.get(); char ascii[ SEGY_TEXT_HEADER_SIZE + 1 ] = {}; const Err err = segy_read_textheader( fp, ascii ); CHECK( err == Err::ok() ); CHECK( ascii == expected ); } SCENARIO( "reading a large file", "[c.segy]" ) { GIVEN( "a large file" ) { const char* file = "4G-file.sgy"; unique_segy ufp( segy_open( file, "w+b" ) ); auto fp = ufp.get(); const int trace = 5000000; const int trace_bsize = 1000; const long long tracesize = trace_bsize + SEGY_TRACE_HEADER_SIZE; const long trace0 = 0; const Err err = segy_seek( fp, trace, trace0, trace_bsize ); CHECK( err == Err::ok() ); WHEN( "reading past 4GB (pos >32bit)" ) { THEN( "there is no overflow" ) { const long long pos = segy_ftell( fp ); CHECK( pos > std::numeric_limits< int >::max() ); CHECK( pos != -1 ); CHECK( pos == trace * tracesize ); } } } } SCENARIO( "reading a 2-byte int file", "[c.segy][2-byte]" ) { unique_segy ufp{ openfile( "test-data/f3.sgy", "rb" ) }; auto fp = ufp.get(); WHEN( "finding traces initial byte offset and sizes" ) { char header[ SEGY_BINARY_HEADER_SIZE ]; REQUIRE( Err( segy_binheader( fp, header ) ) == Err::ok() ); int samples = segy_samples( header ); long trace0 = segy_trace0( header ); int format = segy_format( header ); int trace_bsize = segy_trsize( format, samples ); THEN( "the correct values are inferred from the binary header" ) { CHECK( format == SEGY_SIGNED_SHORT_2_BYTE ); CHECK( trace0 == 3600 ); CHECK( samples == 75 ); CHECK( trace_bsize == 75 * 2 ); } WHEN( "the format is valid" ) THEN( "setting format succeeds" ) { Err err = segy_set_format( fp, format ); CHECK( err == Err::ok() ); } WHEN( "the format is invalid" ) THEN( "setting format fails" ) { Err err = segy_set_format( fp, 50 ); CHECK( err == Err::args() ); } } const int format = SEGY_SIGNED_SHORT_2_BYTE; const long trace0 = 3600; const int samples = 75; const int trace_bsize = samples * 2; WHEN( "reading data without setting format" ) { std::int16_t val; Err err = segy_readsubtr( fp, 10, 25, 26, 1, &val, nullptr, trace0, trace_bsize ); CHECK( err == Err::ok() ); err = segy_to_native( format, sizeof( val ), &val ); CHECK( err == Err::ok() ); THEN( "the value is incorrect" ) { CHECK( val != -1170 ); } } Err err = segy_set_format( fp, format ); REQUIRE( err == Err::ok() ); WHEN( "determining number of traces" ) { int traces = 0; err = segy_traces( fp, &traces, trace0, trace_bsize ); REQUIRE( err == Err::ok() ); CHECK( traces == 414 ); GIVEN( "trace0 outside its domain" ) { WHEN( "trace0 is after end-of-file" ) { err = segy_traces( fp, &traces, 500000, trace_bsize ); THEN( "segy_traces fail" ) CHECK( err == Err::args() ); THEN( "the input does not change" ) CHECK( traces == 414 ); } WHEN( "trace0 is negative" ) { err = segy_traces( fp, &traces, -1, trace_bsize ); THEN( "segy_traces fail" ) CHECK( err == Err::args() ); THEN( "the input does not change" ) CHECK( traces == 414 ); } } } const int traces = 414; const int ilines = 23; const int xlines = 18; const int offset_label = 0; regular_geometry( fp, traces, trace0, trace_bsize, ilines, xlines, offset_label ); const int offsets = 1; const int il = SEGY_TR_INLINE; const int sorting = SEGY_INLINE_SORTING; WHEN( "inferring inline structure" ) { std::vector< int > indices( 23, 0 ); std::iota( indices.begin(), indices.end(), 111 ); WHEN( "finding inline numbers" ) { std::vector< int > result( ilines ); err = segy_inline_indices( fp, il, sorting, ilines, xlines, offsets, result.data(), trace0, trace_bsize ); CHECK( err == Err::ok() ); CHECK_THAT( result, Catch::Equals( indices ) ); } } WHEN( "reading a trace header" ) { char buf[ SEGY_TRACE_HEADER_SIZE ] = {}; GIVEN( "a valid field" ) { err = segy_traceheader( fp, 0, buf, trace0, trace_bsize ); CHECK( err == Err::ok() ); int ilno = 0; err = segy_get_field( buf, SEGY_TR_INLINE, &ilno ); CHECK( err == Err::ok() ); CHECK( ilno == 111 ); } GIVEN( "an invalid field" ) { int x = -1; err = segy_get_field( buf, SEGY_TRACE_HEADER_SIZE + 10, &x ); CHECK( err == Err::field() ); CHECK( x == -1 ); err = segy_get_field( buf, SEGY_TR_INLINE + 1, &x ); CHECK( err == Err::field() ); CHECK( x == -1 ); } } WHEN( "reading a subtrace" ) { const std::vector< slice > inputs = { { 20, 45, 5 }, { 40, 20, -5 }, { 53, 50, -1 }, }; /* * these values have been manually checked with numpy, with this: * https://github.com/Statoil/segyio/issues/238#issuecomment-373735526 */ const std::vector< std::vector< std::int16_t > > expect = { { 0, -1170, 5198, -2213, -888 }, { -888, -2213, 5198, -1170, 0 }, {-2609, -2625, 681 }, }; for( size_t i = 0; i < inputs.size(); ++i ) { WHEN( "slice is " + str( inputs[ i ] ) ) { std::vector< std::int16_t > buf( expect[ i ].size() ); auto start = inputs[ i ].start; auto stop = inputs[ i ].stop; auto step = inputs[ i ].step; err = segy_readsubtr( fp, 10, start, stop, step, buf.data(), nullptr, trace0, trace_bsize ); segy_to_native( format, buf.size(), buf.data() ); CHECK( err == Err::ok() ); CHECK_THAT( buf, Catch::Equals( expect[ i ] ) ); } } } } SCENARIO( "checking sorting for wonky files", "[c.segy]" ) { WHEN( "checking sorting when il, xl and offset is all garbage ") { /* * In the case where all tracefields ( il, xl, offset ) = ( 0, 0, 0 ) * the sorting detection should return 'SEGY_INVALID_SORTING'. To test * this the traceheader field 'SEGY_TR_SEQ_LINE', which we know is zero * in all traceheaders in file small.sgy, is passed to segy_sorting as * il, xl and offset. */ unique_segy ufp{ openfile( "test-data/small.sgy", "rb" ) }; auto fp = ufp.get(); char header[ SEGY_BINARY_HEADER_SIZE ]; REQUIRE( Err( segy_binheader( fp, header ) ) == Err::ok() ); long trace0 = segy_trace0( header ); int samples = segy_samples( header ); int format = segy_format( header ); int trace_bsize = segy_trsize( format, samples ); int sorting; int err = segy_sorting( fp, SEGY_TR_SEQ_LINE, SEGY_TR_SEQ_LINE, SEGY_TR_SEQ_LINE, &sorting, trace0, trace_bsize ); CHECK( err == SEGY_OK ); CHECK( sorting == SEGY_UNKNOWN_SORTING ); } WHEN( "checking sorting when file have dimentions 1x1 ") { const char* file = "test-data/1x1.sgy"; unique_segy ufp( segy_open( file, "rb" ) ); auto fp = ufp.get(); testcfg::config().mmap( fp ); char header[ SEGY_BINARY_HEADER_SIZE ]; REQUIRE( Err( segy_binheader( fp, header ) ) == Err::ok() ); long trace0 = segy_trace0( header ); int samples = segy_samples( header ); int format = segy_format( header ); int trace_bsize = segy_trsize( format, samples ); int sorting; int err = segy_sorting( fp, SEGY_TR_INLINE, SEGY_TR_CROSSLINE, SEGY_TR_OFFSET, &sorting, trace0, trace_bsize ); CHECK( err == SEGY_OK ); CHECK( sorting == SEGY_CROSSLINE_SORTING ); } WHEN( "checking sorting when file have dimentions 1xN ") { const char* file = "test-data/1xN.sgy"; unique_segy ufp( segy_open( file, "rb" ) ); auto fp = ufp.get(); testcfg::config().mmap( fp ); char header[ SEGY_BINARY_HEADER_SIZE ]; REQUIRE( Err( segy_binheader( fp, header ) ) == Err::ok() ); long trace0 = segy_trace0( header ); int samples = segy_samples( header ); int format = segy_format( header ); int trace_bsize = segy_trsize( format, samples ); int sorting; int err = segy_sorting( fp, SEGY_TR_INLINE, SEGY_TR_CROSSLINE, SEGY_TR_OFFSET, &sorting, trace0, trace_bsize ); CHECK( err == SEGY_OK ); CHECK( sorting == SEGY_INLINE_SORTING ); } } segyio-1.8.3/lib/test/segyio-cpp.cpp0000664000372000037200000001534013407674361016752 0ustar travistravis#include #include "matchers.hpp" #include using namespace segyio; using namespace segyio::literals; TEST_CASE( "strong typedef string same has noexcept as string", "[c++]" ) { auto lhs = "lhs"_path; auto rhs = "rhs"_path; std::string strlhs = "lhs"; std::string strrhs = "rhs"; using std::swap; auto str_noexcept = noexcept( swap( strlhs, strrhs ) ); auto path_noexcept = noexcept( swap( lhs, rhs ) ); CHECK( str_noexcept == path_noexcept ); } TEST_CASE( "strong typedef int swap is noexcept", "[c++]" ) { segyio::ilbyte lhs; segyio::ilbyte rhs; auto is_noexcept = noexcept( std::swap( lhs, rhs ) ); CHECK( is_noexcept ); } TEST_CASE( "unstructured throws on non-existing paths", "[c++]" ) { CHECK_THROWS( unstructured( "garbage"_path ) ); } struct Unstructured { Unstructured() : f( "test-data/small.sgy"_path ) {} unstructured f; }; TEST_CASE_METHOD( Unstructured, "unstructured file is copyable", "[c++]" ) { const auto copyable = std::is_copy_constructible< decltype(f) >::value; CHECK( copyable ); } TEST_CASE_METHOD( Unstructured, "unstructured file is movable", "[c++]" ) { const auto movable = std::is_move_constructible< decltype(f) >::value; CHECK( movable ); } TEST_CASE_METHOD( Unstructured, "unstructured reads correct trace metadata", "[c++]" ) { const auto samplecount = 50; const auto format = fmt::ibm(); const auto trace0 = SEGY_TEXT_HEADER_SIZE + SEGY_BINARY_HEADER_SIZE; const auto tracesize = samplecount * 4; const auto tracecount = 25; CHECK( f.samplecount() == samplecount ); CHECK( f.format() == format ); CHECK( f.trace0() == trace0 ); CHECK( f.tracesize() == tracesize ); CHECK( f.tracecount() == tracecount ); } TEST_CASE_METHOD( Unstructured, "unstructured can read an arbitrary trace", "[c++]" ) { const auto samplecount = 50; std::vector< float > out; f.get( 0, std::back_inserter( out ) ); CHECK( out.size() == samplecount ); CHECK( out.at( 0 ) == Approx( 1.20 ) ); } TEST_CASE_METHOD( Unstructured, "unstructured can get trace headers", "[c++]" ) { auto x = f.get_th( 0 ); auto y = f.get_th( 1 ); auto z = f.get_th( 5 ); CHECK( x.iline == 1 ); CHECK( y.iline == 1 ); CHECK( z.iline == 2 ); CHECK( x.xline == 20 ); CHECK( y.xline == 21 ); CHECK( z.xline == 20 ); } TEST_CASE_METHOD( Unstructured, "unstructured can get binary header", "[c++]" ) { auto x = f.get_bin(); CHECK( x.format == 1 ); CHECK( x.samples == 50 ); CHECK( x.interval == 4000 ); CHECK( x.traces == 25); } struct move_only { using filetype = basic_unstructured< disable_copy, open_status >; filetype f; move_only() : f( "test-data/small.sgy"_path ) {} }; TEST_CASE_METHOD( move_only, "basic move-only file is non-copyable", "[c++]" ) { auto copyable = std::is_copy_constructible< decltype(f) >::value; auto movable = std::is_move_constructible< decltype(f) >::value; CHECK_FALSE( copyable ); CHECK( movable ); } TEST_CASE_METHOD( move_only, "a moved-assigned-from file is closed", "[c++]" ) { decltype(f) dst = std::move( f ); CHECK( !f.is_open() ); CHECK( dst.is_open() ); } TEST_CASE_METHOD( move_only, "a moved-constructed-from file is closed", "[c++]" ) { decltype(f) dst( std::move( f ) ); CHECK( !f.is_open() ); CHECK( dst.is_open() ); } struct Closable { using filetype = basic_unstructured< open_status, closable >; filetype f; Closable() : f( "test-data/small.sgy"_path ) {} }; TEST_CASE_METHOD( Closable, "closable file can bve closed", "[c++]" ) { REQUIRE( f.is_open() ); f.close(); CHECK( !f.is_open() ); } TEST_CASE_METHOD( Closable, "copying-and-closing leaves other intact", "[c++]" ) { auto g = f; REQUIRE( f.is_open() ); REQUIRE( g.is_open() ); SECTION( "closing copy leaves original intact" ) { g.close(); CHECK( f.is_open() ); CHECK( !g.is_open() ); } SECTION( "closing original leaves copy intact" ) { f.close(); CHECK( g.is_open() ); CHECK( !f.is_open() ); } } struct Openable { using filetype = basic_unstructured< open_status, openable >; filetype f; }; TEST_CASE_METHOD( Openable, "open can be deferred", "[c++]" ) { REQUIRE( !f.is_open() ); f.open( "test-data/small.sgy"_path ); CHECK( f.is_open() ); } TEST_CASE( "file can be opened as write_always", "[c++]" ) { using F = basic_unstructured< write_always >; F f( "test-data/small.sgy"_path ); } TEST_CASE( "default constructibility can be disabled", "[c++]" ) { using F = basic_unstructured< disable_default >; constexpr auto default_ctor = std::is_default_constructible< F >::value; CHECK_FALSE( default_ctor ); } TEST_CASE( "bounds-checked throws on out-of-range trace access", "[c++]" ) { using F = basic_unstructured< trace_bounds_check >; F f( "test-data/small.sgy"_path ); std::vector< float > out; CHECK_THROWS_AS( f.get( 25, std::back_inserter( out ) ), std::out_of_range ); CHECK_THROWS_AS( f.get( 1000, std::back_inserter( out ) ), std::out_of_range ); CHECK_THROWS_AS( f.get( -1, std::back_inserter( out ) ), std::out_of_range ); } struct Writable { unstructured_writable f; Writable() : f( "test-data/small-w.sgy"_path, config{}.with(mode::readwrite()) ) {} }; TEST_CASE_METHOD( Writable, "unstructured_writable can put trace", "[c++]" ) { std::vector< float > in( 50 ); for( std::size_t i = 0; i < in.size(); ++i ) in[i] = i; f.put( 0, in.begin() ); std::vector< float > out; f.get( 0, std::back_inserter( out ) ); CHECK_THAT( out, ApproxRange( in ) ); } struct Volume { basic_volume<> f; Volume() : f( "test-data/small.sgy"_path ) {} }; TEST_CASE_METHOD( Volume, "volume reads correct metadata from file", "[c++]" ) { const auto inlines = 5; const auto crosslines = 5; const auto offsets = 1; const auto sorting = segyio::sorting::iline(); CHECK( f.inlinecount() == inlines ); CHECK( f.crosslinecount() == crosslines ); CHECK( f.offsetcount() == offsets ); CHECK( f.sorting() == sorting ); } segyio-1.8.3/lib/experimental/0000775000372000037200000000000013407674361015702 5ustar travistravissegyio-1.8.3/lib/experimental/segyio/0000775000372000037200000000000013407674361017201 5ustar travistravissegyio-1.8.3/lib/experimental/segyio/segyio.hpp0000664000372000037200000015214713407674361021223 0ustar travistravis#ifndef SEGYIO_HPP #define SEGYIO_HPP #include #include #include #include #include #include #include #include #include #include #include /* * KNOWN ISSUES AND TODOs: * * 1. consider strong typedef for traceno, lineno etc. * 2. improved naming, especially of final handles * 3. slicing support * 4. proper line read/write support * 5. support for creating files * 6. support for imposing or customising geometry * 7. add get_at/put_at for bounds-checked on-demand */ namespace segyio { namespace detail { struct segy_file_deleter { void operator()( segy_file* fp ) const noexcept(true) { if( fp ) segy_close( fp ); } }; /* * segyio uses strong typedefs [1] around all parameters, for two primary * reasons: * * 1. to explicitly document (and enforce) the intention and role of parameters * 2. to provide customisation points for traits * * Essentially, ensures that: * * file f( "path.sgy"_path ); // compiles * file g( "path.sgy" ); // fails * * The customisation points is described in more detail in the implementation * * [1] https://foonathan.net/blog/2016/10/19/strong-typedefs.html */ /* import swap for ADL */ using std::swap; template< typename Tag, typename T > class strong_typedef { public: using value_type = T; constexpr static bool nothrow_copy_constructible = std::is_nothrow_copy_constructible< value_type >::value; constexpr static bool nothrow_move_constructible = std::is_nothrow_move_constructible< value_type >::value; constexpr static bool nothrow_swappable = noexcept( swap( std::declval< T& >(), std::declval< T& >() ) ); strong_typedef() = default; explicit strong_typedef( const T& x ) noexcept(strong_typedef::nothrow_copy_constructible); explicit strong_typedef( T&& x ) noexcept(strong_typedef::nothrow_move_constructible); explicit operator T&() noexcept(true); explicit operator const T&() const noexcept(true); private: T value; /* * Inherit the noexcept property of the underlying swap operation. Usually * swap is noexcept (although for strings it's only conditionally after * C++17, and not really at all before */ friend void swap( strong_typedef& a, strong_typedef& b ) noexcept( nothrow_swappable ) { swap( static_cast< T& >( a ), static_cast< T& >( b ) ); } }; template< typename Tag, typename T > bool operator==( const strong_typedef< Tag, T >& lhs, const strong_typedef< Tag, T >& rhs ) noexcept(true); template< typename Tag, typename T > bool operator<( const strong_typedef< Tag, T >& lhs, const strong_typedef< Tag, T >& rhs ) noexcept(true); } /* * Typedefs */ struct path : detail::strong_typedef< path, std::string > { using detail::strong_typedef< path, std::string >::strong_typedef; }; struct mode : detail::strong_typedef< mode, std::string > { using detail::strong_typedef< mode, std::string >::strong_typedef; static mode readonly() { return mode{ "r" }; } static mode readwrite() { return mode{ "r+" }; } static mode truncate() { return mode{ "w+" }; } }; struct ilbyte : detail::strong_typedef< ilbyte, int > { ilbyte() : ilbyte( SEGY_TR_INLINE ) {} using detail::strong_typedef< ilbyte, int >::strong_typedef; }; struct xlbyte : detail::strong_typedef< xlbyte, int > { xlbyte() : xlbyte( SEGY_TR_CROSSLINE ) {} using detail::strong_typedef< xlbyte, int >::strong_typedef; }; struct fmt : detail::strong_typedef< fmt , int > { private: using Base = detail::strong_typedef< fmt, int >; public: static fmt ibm() { return fmt{ SEGY_IBM_FLOAT_4_BYTE }; } static fmt ieee() { return fmt{ SEGY_IEEE_FLOAT_4_BYTE }; } static fmt int4() { return fmt{ SEGY_SIGNED_INTEGER_4_BYTE }; } static fmt int2() { return fmt{ SEGY_SIGNED_SHORT_2_BYTE }; } static fmt int1() { return fmt{ SEGY_SIGNED_CHAR_1_BYTE }; } fmt(); explicit fmt( int x ) noexcept(false); const char* description() const noexcept(true); }; struct sorting : detail::strong_typedef< sorting, int > { private: using Base = detail::strong_typedef< sorting, int >; public: static sorting iline() { return sorting{ SEGY_INLINE_SORTING }; }; static sorting xline() { return sorting{ SEGY_CROSSLINE_SORTING }; }; sorting(); explicit sorting( int x ) noexcept(false); const char* description() const noexcept(true); }; namespace literals { inline path operator"" _path( const char* name, std::size_t ) { return path{ name }; } inline mode operator"" _mode( const char* name, std::size_t ) { return mode{ name }; } inline ilbyte operator"" _il( unsigned long long x ) { return ilbyte{ int( x ) }; } inline xlbyte operator"" _xl( unsigned long long x ) { return xlbyte{ int( x ) }; } inline fmt operator"" _fmt( unsigned long long x ) { return fmt{ int( x ) }; } } namespace { /* * This (unavailable) namespace implements the main dispatch mechanism for * customisation points, i.e. where control is given to traits (mixins). * * Traits implement custom behaviour for a customisation point by implementing * the operator() for a specific type * * Once you strip away all the line noise that is C++ template metaprogramming, * it's a fairly simple procecure: at a customisation point, look at every * trait, and execute operator() if it exists. In code: * * type = customisation-point.type * for trait in traits: * if trait.has-overload(type): * trait.call(type) * * This meta program is run at compile time. If a trait does not define a * (public) operator() for that particular type, it calls a no-op substitute * function, which will be killed by the optimiser. * * Use the strong_typedef in segyio::detail to create new types for * customisation points, if it is based on a simpler type (like std::string). */ /* * invocable is an emulation of the C++17 std::is_invocable * * For our purposes, it's the check: does F.operator()( Args... ) exist? */ template< typename F, typename... Args > using invocable = std::is_constructible< std::function< void( Args &&... ) >, std::reference_wrapper< typename std::remove_reference< F >::type > >; template< typename F, typename... Arg > using enable_if_invocable = std::enable_if< invocable< F, Arg... >::value >; template< typename F, typename... Arg > using disable_if_invocable = std::enable_if< !invocable< F, Arg... >::value >; /* * if exists F.operator()(Args) exists, call it */ template< typename F, typename... Args > typename enable_if_invocable< F, Args... >::type call_if_exists( F& f, Args&& ... x ) { f( std::forward< Args >( x ) ... ); } /* * if not, just do nothing and let the optimiser kill it */ template< typename F, typename... Arg > typename disable_if_invocable< F, Arg... >::type call_if_exists( F&, Arg && ... ) {} /* * the template< typename > class... trick allows multiple sets of parameter * packs. otherwise, the first paramter pack would always swallow the remaining * template parameters. This adds support for consider() with multiple * arguments. */ template< template< typename > class... Traits, class Base, typename... Args > void apply_all( Base& f, Args && ... args ) { /* * "for-each-argument" * https://isocpp.org/blog/2015/01/for-each-argument-sean-parent * * This fenomenal trick walks the list of traits and either calls the * approperate F.operator(), or sets the no-op. * * In essence, it casts the base to every mixin and lets the invocable * machinery figure out what to do with it (to inject operator() or a * no-op). In C++17 this can pretty much be reduced to a fold expression. * * Traits are *always* called left-to-right [1], so if operations have some * dependency it is *crucial* that all dependencies are to the left in the * trait-list. * * [1] this is guaranteed by the int[] aggregate, see the isocpp link for * details. */ using arrayt = int[]; static_cast(arrayt{( call_if_exists(static_cast< Traits< Base >& >(f), std::forward< Args >( args ) ... ), 0) ... }); } } namespace { /* * backport std::conjunction and std::disjunction from C++17, if unavailable, * needed for has_any and has_all * * https://en.cppreference.com/w/cpp/types/conjunction * https://en.cppreference.com/w/cpp/types/disjunction */ #ifdef __cpp_lib_logical_traits using std::conjunction; using std::disjunction; #else template< typename... > struct conjunction : std::true_type {}; template< typename B1 > struct conjunction< B1 > : B1 {}; template< typename B1, class... Bn > struct conjunction< B1, Bn... > : std::conditional, B1>::type {}; template< typename... > struct disjunction : std::false_type {}; template< typename B1 > struct disjunction< B1 > : B1 {}; template< typename B1, class... Bn > struct disjunction< B1, Bn... > : std::conditional>::type {}; #endif } /* * Check if the file handle has any or all of the mentioned traits, useful for * compile-time selection of overloads or querying features */ template< typename File, template< typename > class... Traits > using all_traits = conjunction< std::is_base_of< Traits< File >, File > ... >; template< typename File, template< typename > class... Traits > using any_traits = disjunction< std::is_base_of< Traits< File >, File > ... >; /* * CONFIG */ struct config { segyio::mode mode = segyio::mode::readonly(); ilbyte iline; xlbyte xline; /* in C++14 could be tuple with get< type > */ config& with( segyio::mode x ) { this->mode = x; return *this; } config& with( ilbyte x ) { this->iline = x; return *this; } config& with( xlbyte x ) { this->xline = x; return *this; } }; /* * The stupid basic file that keeps on learning new skills * * The segyio C++ file handle is based on variadic CRTP [1], which in short * means a stupid base class with a bunch of template parameters that * encapsulate and describe a certain behaviour, restriction, or guarantee. * * The motivation for this is to provide fine-grained static guarantees for * file handles, such as: * * - this file MUST be a cube * - this file is *never* writable * - this file is *always* writable * - this file handle cannot be copied by accident (is unique) * - as long as this handle lives, the file is open (always-alive) * * All these properties can be made and proven staticially, and means users * never really have to check at runtime (at least manually). Aditionally, * users can implement their own custom restrictions and new behaviours, and * add at their leisure. * * To add a new trait, write any class and add it to the template parameter * list of basic_path. Any public method will be available in the resulting * file handle. * * Syntactically this is all pretty heavy, but the end-user experience should * be nice, and this shouldn't be visible at all * * [1] https://www.fluentcpp.com/2018/06/22/variadic-crtp-opt-in-for-class-features-at-compile-time/ */ template< template< typename... > class ... Traits > class basic_file : public Traits< basic_file< Traits... > >... { public: /* * method version of all/any traits. Useful when you're in a context where * an instance is already available, and a quite natural way of checking * for either features or that requirements are maintained. * * please note that the method must be called as * f.template all_traits to enforce second-phase lookup. * * Example use: * * template< typename Derived > * struct Trait { * void foo() { * auto* self = static_cast< Derived >( this ); * static_assert( self->template know_all< Trait1, Trait2 >(), * "foo requires Trait1 (bar) and Trait2 (baz)" ); * self->bar(); * self->baz(); * } * }; */ template< template< typename > class... Trait > static constexpr bool know_all() { return all_traits< basic_file, Trait... >::value; } template< template< typename > class... Trait > static constexpr bool know_any() { return any_traits< basic_file, Trait... >::value; } basic_file() = default; /* * The initialisation list is a mega hack * * The problem is traits that disallows default construction of a file * handle, or in some other way mess with the default constructor. * Disabling default construction is an attractive property, because it * means that if a program compiles then it *has* to always open a file on * object initalisation, and if it constructs without throwing then you * know your file is alive, and in a valid state. In code: * * using F = basic_path< ... >; * F with_path( "file.sgy"_path ); // ok * F g; // error, F() = delete * * The problem is that simply disabling the default constructor in the * trait means that it cannot be default-initialised, even when using a * non-default-constructor. But, since presumably this trait is otherwise * empty, it is also an aggregate type, and {}-intialisation works, so * simply {}-construct all traits and copy- or move-construct them into our * own members. * * The optimiser should go ham on this and simply elide everything, while * still providing the correct static guarantees. */ basic_file( const segyio::path& path, const segyio::config& cfg = config() ) noexcept(false) : Traits< basic_file >( {} ) ... { this->consider( path ); auto mode = this->consider( cfg.mode ); this->open_path( path, mode ); this->consider( this->escape() ); this->consider( this->escape(), cfg ); } /* * operator()(Arg) is used for customisation points, but these are internal * and should not pollute the basic_path interface. Disallow F(Arg) without * an explicit static_cast */ template< typename... A > void operator()( A && ... ) = delete; template< typename Arg, typename... Args > Arg consider( Arg arg, Args && ... args ) { apply_all< Traits... >( *this, arg, std::forward< Args >( args ) ... ); return arg; } }; /* * Traits, and their requirements */ /* * tags for writability and truncability. * * A truncable file is always writable, but most write-enforcing traits will * also enforce non-truncable, to not accidently destroy files. * * Custom traits that allows or enforce write/trunc behaviour should inherit * from these tags, to improve correctness verification of other traits. */ template< typename > struct writable {}; template< typename T > struct truncable : writable< T > {}; template< typename > class simple_handle { /* * The simple_handle is the simplest form of a managed file handle, with * copy-opens-new-handle semantics, and completely implements the file * handle concept. * * The file handle concept requires the following (compatible) interface * * types: * ptr_type, a unique_ptr interface compatible type. * * public methods: * ptr_type& get_unique() * segy_file* escape() * * protected methods: * void open_path( const path&, const mode& ); * * ptr_type does not have to be exported */ public: using ptr_type = std::unique_ptr< segy_file, detail::segy_file_deleter >; ptr_type& get_unique() noexcept(true); segy_file* escape() noexcept(true); const segy_file* escape() const noexcept(true); simple_handle() = default; simple_handle( simple_handle&& ) = default; simple_handle& operator=( const simple_handle& ) = default; simple_handle& operator=( simple_handle&& ) = default; simple_handle( const simple_handle& o ) noexcept(false); protected: simple_handle( const segyio::path&, const segyio::mode& ) noexcept(false); void open_path( const segyio::path& path, const segyio::mode& ) noexcept(false); private: ptr_type fp; segyio::path path; segyio::mode mode; }; template< typename > struct simple_buffer { char* buffer() noexcept(true); const char* buffer() const noexcept(true); void buffer_resize( std::size_t size ) noexcept(true); std::size_t buffer_size() const noexcept(true); private: std::vector< char > buf; }; template< typename > struct disable_copy { disable_copy( const disable_copy& ) = delete; disable_copy& operator=( const disable_copy& ) = delete; disable_copy() = default; disable_copy( disable_copy&& ) = default; disable_copy& operator=( disable_copy&& ) = default; }; template< typename Derived > struct closable { void close() noexcept(true); }; template< typename Derived > struct openable { void open( const segyio::path&, const segyio::config& cfg = {} ) noexcept(false); }; template< typename Derived > struct open_status { bool is_open() const noexcept(true); }; template< typename Derived > struct readonly { void operator()( const mode& out ) const noexcept(false); }; template< typename Derived > struct disable_truncate { void operator()( mode& out ) const noexcept(false); }; template< typename Derived > struct write_always : public writable< Derived > { void operator()( mode& out ) const noexcept(false); }; template< typename Derived > struct truncate_always : public truncable< Derived > { void operator()( mode& out ) const noexcept(false); }; /* * The trace_metadata concept is the basic file metadata. For standard * compliant files this is inferred from the binary header. * * Most traits require a stats concept, because stats provide the basic * information used to navigate the file. * * trace_metadata should provide: * * int samplecount() - samplecount-per-trace * fmt format() - data format * long trace0() - offset of first trace past extended text headers * int tracesize() - size of each trace in bytes * int tracecount() - number of traces in this file */ template< typename Derived > struct trace_meta_fromfile { int samplecount() const noexcept(true); segyio::fmt format() const noexcept(true); long trace0() const noexcept(true); int tracesize() const noexcept(true); int tracecount() const noexcept(true); void operator()( segy_file* fp ) noexcept(false); private: long tr0 = 0; int trsize = 0; int smp = 0; int traces = 0; segyio::fmt fmt; }; struct binary_header { int job_identification = 0; int line = 0; int reel = 0; int traces = 0; int auxiliary_traces = 0; int interval = 0; int interval_orig = 0; int samples = 0; int samples_orig = 0; int format = 0; int ensemble_fold = 0; int sorting = 0; int vertical_sum = 0; int sweep_freq_start = 0; int sweep_freq_end = 0; int sweep_length = 0; int sweep_type = 0; int sweep_channel = 0; int sweep_taperlen_start = 0; int sweep_taperlen_end = 0; int taper_type = 0; int correlated = 0; int binary_gain_recovery = 0; int amplitude_recovery = 0; int measurement_system = 0; int impulse_polarity = 0; int vibratory_polarity = 0; int segy_revision = 0; int trace_flag = 0; int extended_textheaders = 0; }; template< typename Derived > struct binary_header_reader{ binary_header get_bin() noexcept(false); }; template< typename Derived > struct trace_bounds_check { void operator()( int i ) const noexcept(false); }; template< typename Derived > struct trace_reader { template< typename OutputIt > OutputIt get( int i, OutputIt out ) noexcept(false); void operator()( const segy_file* ) noexcept(false); }; struct trace_header { int sequence_line = 0; int sequence_file = 0; int field_record = 0; int traceno_orig = 0; int energy_source_point = 0; int ensemble = 0; int traceno = 0; int trace_id = 0; int summed_traces = 0; int stacked_traces = 0; int data_use = 0; int offset = 0; int elevation_receiver = 0; int elevation_source = 0; int depth_source = 0; int datum_receiver = 0; int datum_source = 0; int depth_water_source = 0; int depth_water_group = 0; int elevation_scalar = 0; int coord_scalar = 0; int source_x = 0; int source_y = 0; int group_x = 0; int group_y = 0; int coord_units = 0; int weathering_velocity = 0; int subweathering_velocity = 0; int uphole_source = 0; int uphole_group = 0; int static_source = 0; int static_group = 0; int static_total = 0; int lag_a = 0; int lag_b = 0; int delay = 0; int mute_start = 0; int mute_end = 0; int samples = 0; int sample_interval = 0; int gain_type = 0; int gain_constant = 0; int gain_initial = 0; int correlated = 0; int sweep_freq_start = 0; int sweep_freq_end = 0; int sweep_length = 0; int sweep_type = 0; int sweep_taperlen_start = 0; int sweep_taperlen_end = 0; int taper_type = 0; int alias_filt_freq = 0; int alias_filt_slope = 0; int notch_filt_freq = 0; int notch_filt_slope = 0; int low_cut_freq = 0; int high_cut_freq = 0; int low_cut_slope = 0; int high_cut_slope = 0; int year = 0; int day = 0; int hour = 0; int min = 0; int sec = 0; int timecode = 0; int weighting_factor = 0; int geophone_group_roll1 = 0; int geophone_group_first = 0; int geophone_group_last = 0; int gap_size = 0; int over_travel = 0; int cdp_x = 0; int cdp_y = 0; int iline = 0; int xline = 0; int shot_point = 0; int shot_point_scalar = 0; int unit = 0; int transduction_mantissa = 0; int transduction_exponent = 0; int transduction_unit = 0; int device_id = 0; int scalar_trace_header = 0; int source_type = 0; int source_energy_dir_mant = 0; int source_energy_dir_exp = 0; int source_measure_mant = 0; int source_measure_exp = 0; int source_measure_unit = 0; }; template< typename Derived > struct trace_header_reader { trace_header get_th( int i ) noexcept(false); }; template< typename Derived > struct trace_writer { template< typename InputIt > InputIt put( int i, InputIt in ); }; template< typename Derived > struct volume_meta_fromfile { volume_meta_fromfile() = default; segyio::sorting sorting() const noexcept(true); int inlinecount() const noexcept(true); int crosslinecount() const noexcept(true); int offsetcount() const noexcept(true); void operator()( segy_file* fp, const config& cfg ) noexcept(false); private: segyio::sorting sort; int ilines; int xlines; int offs; }; template< typename > struct disable_default { disable_default() = delete; }; template< template< typename > class... Extras > using basic_unstructured = basic_file< simple_handle, simple_buffer, trace_meta_fromfile, binary_header_reader, trace_reader, trace_header_reader, disable_truncate, Extras... >; using unstructured = basic_unstructured<>; using unstructured_readonly = basic_unstructured< readonly >; using unstructured_writable = basic_unstructured< writable, trace_writer >; template< template< typename > class... Extras > using basic_volume = basic_unstructured< volume_meta_fromfile, Extras... >; namespace { /* * useful helpers */ segy_file* segy_open( const segyio::path& path, const segyio::mode& mode ) noexcept(true) { const auto& p = static_cast< const std::string& >(path); const auto& m = static_cast< const std::string& >(mode); return ::segy_open( p.c_str(), m.c_str() ); } template< typename T, typename OutputIt > OutputIt copy_n_as( int n, const void* p, OutputIt out ) { const auto* typed = reinterpret_cast< const T* >( p ); return std::copy_n( typed, n, out ); } std::runtime_error errnomsg( const std::string& msg ) { return std::runtime_error(msg + ": " + std::strerror( errno ) ); } std::runtime_error unknown_error( int errc ) { std::string msg = "unhandled error (code " + std::to_string( errc ) + ")"; return std::runtime_error( msg ); } } /* * Implementations */ namespace detail { template< typename Tag, typename T > strong_typedef< Tag, T >::strong_typedef( const T& x ) noexcept(strong_typedef::nothrow_copy_constructible) : value( x ) {} template< typename Tag, typename T > strong_typedef< Tag, T >::strong_typedef( T&& x ) noexcept(strong_typedef::nothrow_move_constructible) : value( std::move( x ) ) {} template< typename Tag, typename T > strong_typedef< Tag, T >::operator T&() noexcept(true) { return this->value; } template< typename Tag, typename T > strong_typedef< Tag, T >::operator const T&() const noexcept(true) { return this->value; } template< typename Tag, typename T > bool operator==( const strong_typedef< Tag, T >& lhs, const strong_typedef< Tag, T >& rhs ) noexcept(true) { using Base = typename strong_typedef< Tag, T >::value_type; const auto& a = static_cast< const Base& >( lhs ); const auto& b = static_cast< const Base& >( rhs ); return a == b; } template< typename Tag, typename T > bool operator<( const strong_typedef< Tag, T >& lhs, const strong_typedef< Tag, T >& rhs ) noexcept(true) { using Base = typename strong_typedef< Tag, T >::value_type; const auto& a = static_cast< const Base& >( lhs ); const auto& b = static_cast< const Base& >( rhs ); return a < b; } } fmt::fmt() : Base( SEGY_IBM_FLOAT_4_BYTE ) {} fmt::fmt( int x ) noexcept(false) : Base( x ) { switch( x ) { case SEGY_IBM_FLOAT_4_BYTE: case SEGY_SIGNED_INTEGER_4_BYTE: case SEGY_SIGNED_SHORT_2_BYTE: case SEGY_FIXED_POINT_WITH_GAIN_4_BYTE: case SEGY_IEEE_FLOAT_4_BYTE: case SEGY_SIGNED_CHAR_1_BYTE: return; case SEGY_NOT_IN_USE_1: case SEGY_NOT_IN_USE_2: default: throw std::invalid_argument( "unknown format specifier key " + std::to_string(x) ); } } const char* fmt::description() const noexcept(true) { switch( int( *this ) ) { case SEGY_IBM_FLOAT_4_BYTE: return "ibm float"; case SEGY_SIGNED_INTEGER_4_BYTE: return "int"; case SEGY_SIGNED_SHORT_2_BYTE: return "short"; case SEGY_FIXED_POINT_WITH_GAIN_4_BYTE: return "fixed-point float with gain"; case SEGY_IEEE_FLOAT_4_BYTE: return "ieee float"; case SEGY_SIGNED_CHAR_1_BYTE: return "byte"; case SEGY_NOT_IN_USE_1: case SEGY_NOT_IN_USE_2: default: return "unknown"; } } sorting::sorting() : Base( SEGY_INLINE_SORTING ) {} sorting::sorting( int x ) noexcept(false) : Base( x ) { switch( x ) { case SEGY_INLINE_SORTING: case SEGY_CROSSLINE_SORTING: return; case SEGY_UNKNOWN_SORTING: default: throw std::invalid_argument( "unknown sorting specifier " + std::to_string(x) ); } } const char* sorting::description() const noexcept(true) { switch( int(*this) ) { case SEGY_INLINE_SORTING: return "inline"; case SEGY_CROSSLINE_SORTING: return "crossline"; case SEGY_UNKNOWN_SORTING: default: return "unknown"; } } template< typename T > typename simple_handle< T >::ptr_type& simple_handle< T >::get_unique() noexcept(true) { return this->fp; } template< typename T > segy_file* simple_handle< T >::escape() noexcept(true) { return this->fp.get(); } template< typename T > const segy_file* simple_handle< T >::escape() const noexcept(true) { return this->fp.get(); } template< typename T > simple_handle< T >::simple_handle( const simple_handle& o ) noexcept(false) : simple_handle( o.path, o.mode ) {} template< typename T > simple_handle< T >::simple_handle( const segyio::path& path, const segyio::mode& mode ) noexcept(false) : fp( segy_open( path, mode ) ), path( path ), mode( mode ) { if( this->fp ) return; auto m = std::string(mode); const std::string allowed_modes[] = { "r", "r+", "w+", "rb", "r+b", "w+b", }; /* * Allow without 'b', but don't include them in the error message. * * There are VERY few cases where users should use anything but the named * constructors of mode strings, and if they do use literals with trailing * 'b', that's also fine (and won't throw), but to fix issues with the * strings, one of the r/w/+ should be preferred. */ const auto begin = std::begin( allowed_modes ); const auto end = std::end( allowed_modes ); if( std::find( begin, end, m ) == end ) { const auto msg = "mode must be one of r, r+, w+, was " + m; throw std::invalid_argument( msg ); } auto p = std::string(path); std::unique_ptr< std::FILE, decltype( &std::fclose ) > file( std::fopen( p.c_str(), m.c_str() ), std::fclose ); if( file ) { /* mode isn't garbage, and path apparently is ok too */ throw std::runtime_error( "unknown failure in segy_open" ); } // file didn't open, so leverage errno to give a better error message std::string msg = "unable to open " + p + ": " + std::strerror( errno ); throw std::runtime_error( msg ); } template< typename T > void simple_handle< T >::open_path( const segyio::path& path, const segyio::mode& mode ) noexcept(false) { *this = simple_handle( path, mode ); } template< typename T > char* simple_buffer< T >::buffer() noexcept(true) { return this->buf.data(); } template< typename T > const char* simple_buffer< T >::buffer() const noexcept(true) { return this->buf.data(); } template< typename T > void simple_buffer< T >::buffer_resize( std::size_t size ) noexcept(true) { this->buf.resize( size ); } template< typename T > std::size_t simple_buffer< T >::buffer_size() const noexcept(true) { return this->buf.size(); } template< typename Derived > void openable< Derived>::open( const path& path, const config& cfg ) noexcept(false) { static_cast< Derived& >( *this ) = Derived( path, cfg ); } template< typename Derived > void closable< Derived >::close() noexcept(true) { auto* self = static_cast< Derived* >( this ); self->get_unique().reset( nullptr ); } template< typename Derived > void disable_truncate< Derived >::operator()( mode& out ) const noexcept(false) { static_assert( !any_traits< Derived, truncable >::value, "file marked no-truncable, but trait introduces truncability" ); const auto& str = static_cast< const std::string& >( out ); if( str.find( 'w' ) != std::string::npos ) { constexpr auto msg = "mode with 'w' would truncate, " "add a truncate-trait to allow"; throw std::invalid_argument( msg ); } } template< typename Derived > bool open_status< Derived >::is_open() const noexcept(true) { return static_cast< const Derived* >( this )->escape(); } template< typename Derived > void readonly< Derived >::operator()( const mode& out ) const noexcept(false) { static_assert( !any_traits< Derived, writable >::value, "read-only file requested, but a trait introduces writability" ); const std::string& str = static_cast< const std::string& >( out ); const auto write_token_pos = str.find_first_of( "wa+" ); if( write_token_pos == std::string::npos ) return; const std::string msg = str + " enables write (" + str[write_token_pos] + ") in file marked read-only"; throw std::invalid_argument( msg ); } template< typename T > void write_always< T >::operator()( mode& out ) const noexcept(false) { out = mode::readwrite(); } template< typename T > void truncate_always< T >::operator()( mode& out ) const noexcept(false) { out = mode::truncate(); } template< typename T > int trace_meta_fromfile< T >::samplecount() const noexcept(true) { return this->smp; } template< typename T > segyio::fmt trace_meta_fromfile< T >::format() const noexcept(true) { return this->fmt; } template< typename T > long trace_meta_fromfile< T >::trace0() const noexcept(true) { return this->tr0; } template< typename T > int trace_meta_fromfile< T >::tracesize() const noexcept(true) { return this->trsize; } template< typename T > int trace_meta_fromfile< T >::tracecount() const noexcept(true) { return this->traces; } template< typename T > void trace_meta_fromfile< T >::operator()( segy_file* fp ) noexcept(false) { char buffer[ SEGY_BINARY_HEADER_SIZE ] = {}; auto err = segy_binheader( fp, buffer ); switch( err ) { case SEGY_OK: break; case SEGY_FSEEK_ERROR: throw errnomsg( "unable to seek to binary header" ); case SEGY_FREAD_ERROR: throw errnomsg( "unable to read binary header" ); default: throw unknown_error( err ); } auto samplecount = segy_samples( buffer ); auto trace0 = segy_trace0( buffer ); auto format = segyio::fmt{ segy_format( buffer ) }; auto trsize = segy_trsize( int(format), samplecount ); /* * TODO: move sanity-checking these properties to separate trait? To * allow fall-back mechianisms */ if( samplecount <= 0 ) throw std::invalid_argument( "expected samplecount >= 0 (was " + std::to_string( samplecount ) + ")" ); if( trace0 < 0 ) throw std::invalid_argument( "expected trace0 >= 0 (was " + std::to_string( trace0 ) + ")" ); int tracecount; err = segy_traces( fp, &tracecount, trace0, trsize ); switch( err ) { case SEGY_OK: break; case SEGY_INVALID_ARGS: throw std::runtime_error( "first trace position computed after file, " "extended textual header word corrupted " "or file truncated" ); case SEGY_TRACE_SIZE_MISMATCH: throw std::runtime_error( "file size does not evenly divide into traces, " "either traces are of uneven length, " "or trace0 is wrong (was " + std::to_string(trace0) + ")" ); default: throw unknown_error( err ); } /* all good, so actually change state */ this->tr0 = trace0; this->trsize = trsize; this->smp = samplecount; this->traces = tracecount; this->fmt = segyio::fmt{ format }; } template< typename Derived > void trace_bounds_check< Derived >::operator()( int i ) const noexcept(false) { auto* self = static_cast< const Derived* >( this ); if ( i >= 0 && i < self->tracecount() ) return; if ( i < 0 ) { auto msg = "trace_bounds_check: n (which is " + std::to_string(i) + ") < 0"; throw std::out_of_range( msg ); } auto msg = "trace_bounds_check: n (which is " + std::to_string(i) + ") >= this->tracecount() (which is " + std::to_string(self->tracecount()) + ")"; throw std::out_of_range( msg ); } template< typename Derived > template< typename OutputIt > OutputIt trace_reader< Derived >::get( int i, OutputIt out ) noexcept(false) { auto* self = static_cast< Derived* >( this ); auto* fp = self->escape(); self->consider( i ); auto err = segy_readtrace( fp, i, self->buffer(), self->trace0(), self->tracesize() ); switch( err ) { case SEGY_OK: break; case SEGY_FSEEK_ERROR: throw errnomsg( "unable to seek trace " + std::to_string(i) ); case SEGY_FREAD_ERROR: throw errnomsg( "unable to read trace " + std::to_string(i) ); default: throw unknown_error( err ); } const auto format = int(self->format()); const auto samplecount = self->samplecount(); segy_to_native( format, samplecount, self->buffer() ); const auto* raw = self->buffer(); switch( format ) { case SEGY_IBM_FLOAT_4_BYTE: case SEGY_IEEE_FLOAT_4_BYTE: return copy_n_as< float >( samplecount, raw, out ); case SEGY_SIGNED_INTEGER_4_BYTE: return copy_n_as< std::int32_t >( samplecount, raw, out ); case SEGY_SIGNED_SHORT_2_BYTE: return copy_n_as< std::int16_t >( samplecount, raw, out ); case SEGY_SIGNED_CHAR_1_BYTE: return copy_n_as< std::int8_t >( samplecount, raw, out ); default: throw std::runtime_error( std::string("this->format is broken (was ") + self->format().description() + ")" ); } } template< typename Derived > void trace_reader< Derived >::operator()( const segy_file* ) noexcept(false) { auto* self = static_cast< Derived* >( this ); const auto trace_size = self->tracesize(); if ( trace_size == 0 ) { const auto msg = "Trace size (in bytes) not computed " "before buffers are resized. " "Move a Stats trait before the trace_reader " "in the trait list"; throw std::runtime_error( msg ); } self->buffer_resize( trace_size ); } template< typename Derived > binary_header binary_header_reader< Derived >::get_bin() noexcept(false) { char buffer[ SEGY_BINARY_HEADER_SIZE ] = {}; auto* self = static_cast< Derived* >( this ); auto err = segy_binheader( self->escape(), buffer ); switch( err ) { case SEGY_OK: break; case SEGY_FSEEK_ERROR: throw errnomsg( "unable to seek binary header" ); case SEGY_FREAD_ERROR: throw errnomsg( "unable to read binary header" ); default: throw unknown_error( err ); } const auto getb = [&]( int key ) { int32_t f; segy_get_bfield( buffer, key, &f ); return f; }; binary_header b; b.job_identification = getb( SEGY_BIN_JOB_ID ); b.line = getb( SEGY_BIN_LINE_NUMBER ); b.reel = getb( SEGY_BIN_REEL_NUMBER ); b.traces = getb( SEGY_BIN_TRACES ); b.auxiliary_traces = getb( SEGY_BIN_AUX_TRACES ); b.interval = getb( SEGY_BIN_INTERVAL ); b.interval_orig = getb( SEGY_BIN_INTERVAL_ORIG ); b.samples = getb( SEGY_BIN_SAMPLES ); b.samples_orig = getb( SEGY_BIN_SAMPLES_ORIG ); b.format = getb( SEGY_BIN_FORMAT ); b.ensemble_fold = getb( SEGY_BIN_ENSEMBLE_FOLD ); b.sorting = getb( SEGY_BIN_SORTING_CODE ); b.vertical_sum = getb( SEGY_BIN_VERTICAL_SUM ); b.sweep_freq_start = getb( SEGY_BIN_SWEEP_FREQ_START ); b.sweep_freq_end = getb( SEGY_BIN_SWEEP_FREQ_END ); b.sweep_length = getb( SEGY_BIN_SWEEP_LENGTH ); b.sweep_type = getb( SEGY_BIN_SWEEP ); b.sweep_channel = getb( SEGY_BIN_SWEEP_CHANNEL ); b.sweep_taperlen_start = getb( SEGY_BIN_SWEEP_TAPER_START ); b.sweep_taperlen_end = getb( SEGY_BIN_SWEEP_TAPER_END ); b.taper_type = getb( SEGY_BIN_TAPER ); b.correlated = getb( SEGY_BIN_CORRELATED_TRACES ); b.binary_gain_recovery = getb( SEGY_BIN_BIN_GAIN_RECOVERY ); b.amplitude_recovery = getb( SEGY_BIN_AMPLITUDE_RECOVERY ); b.measurement_system = getb( SEGY_BIN_MEASUREMENT_SYSTEM ); b.impulse_polarity = getb( SEGY_BIN_IMPULSE_POLARITY ); b.vibratory_polarity = getb( SEGY_BIN_VIBRATORY_POLARITY ); b.segy_revision = getb( SEGY_BIN_SEGY_REVISION ); b.trace_flag = getb( SEGY_BIN_TRACE_FLAG ); b.extended_textheaders = getb( SEGY_BIN_EXT_HEADERS ); return b; } template< typename Derived > trace_header trace_header_reader< Derived >::get_th( int i ) noexcept(false) { char buffer[ SEGY_TRACE_HEADER_SIZE ] = {}; auto* self = static_cast< Derived* >( this ); self->consider( i ); auto err = segy_traceheader( self->escape(), i, buffer, self->trace0(), self->tracesize() ); switch( err ) { case SEGY_OK: break; case SEGY_FSEEK_ERROR: throw errnomsg( "unable to seek trace " + std::to_string(i) ); case SEGY_FREAD_ERROR: throw errnomsg( "unable to read trace " + std::to_string(i) ); default: throw unknown_error( err ); } const auto getf = [&]( int key ) { int32_t f; segy_get_field( buffer, key, &f ); return f; }; trace_header h; h.sequence_line = getf( SEGY_TR_SEQ_LINE ); h.sequence_file = getf( SEGY_TR_SEQ_FILE ); h.field_record = getf( SEGY_TR_FIELD_RECORD ); h.traceno_orig = getf( SEGY_TR_NUMBER_ORIG_FIELD ); h.energy_source_point = getf( SEGY_TR_ENERGY_SOURCE_POINT ); h.ensemble = getf( SEGY_TR_ENSEMBLE ); h.traceno = getf( SEGY_TR_NUM_IN_ENSEMBLE ); h.trace_id = getf( SEGY_TR_TRACE_ID ); h.summed_traces = getf( SEGY_TR_SUMMED_TRACES ); h.stacked_traces = getf( SEGY_TR_STACKED_TRACES ); h.data_use = getf( SEGY_TR_DATA_USE ); h.offset = getf( SEGY_TR_OFFSET ); h.elevation_receiver = getf( SEGY_TR_RECV_GROUP_ELEV ); h.elevation_source = getf( SEGY_TR_SOURCE_SURF_ELEV ); h.depth_source = getf( SEGY_TR_SOURCE_DEPTH ); h.datum_receiver = getf( SEGY_TR_RECV_DATUM_ELEV ); h.datum_source = getf( SEGY_TR_SOURCE_DATUM_ELEV ); h.depth_water_source = getf( SEGY_TR_SOURCE_WATER_DEPTH ); h.depth_water_group = getf( SEGY_TR_GROUP_WATER_DEPTH ); h.elevation_scalar = getf( SEGY_TR_ELEV_SCALAR ); h.coord_scalar = getf( SEGY_TR_SOURCE_GROUP_SCALAR ); h.source_x = getf( SEGY_TR_SOURCE_X ); h.source_y = getf( SEGY_TR_SOURCE_Y ); h.group_x = getf( SEGY_TR_GROUP_X ); h.group_y = getf( SEGY_TR_GROUP_Y ); h.coord_units = getf( SEGY_TR_COORD_UNITS ); h.weathering_velocity = getf( SEGY_TR_WEATHERING_VELO ); h.subweathering_velocity = getf( SEGY_TR_SUBWEATHERING_VELO ); h.uphole_source = getf( SEGY_TR_SOURCE_UPHOLE_TIME ); h.uphole_group = getf( SEGY_TR_GROUP_UPHOLE_TIME ); h.static_source = getf( SEGY_TR_SOURCE_STATIC_CORR ); h.static_group = getf( SEGY_TR_GROUP_STATIC_CORR ); h.static_total = getf( SEGY_TR_TOT_STATIC_APPLIED ); h.lag_a = getf( SEGY_TR_LAG_A ); h.lag_b = getf( SEGY_TR_LAG_B ); h.delay = getf( SEGY_TR_DELAY_REC_TIME ); h.mute_start = getf( SEGY_TR_MUTE_TIME_START ); h.mute_end = getf( SEGY_TR_MUTE_TIME_END ); h.samples = getf( SEGY_TR_SAMPLE_COUNT ); h.sample_interval = getf( SEGY_TR_SAMPLE_INTER ); h.gain_type = getf( SEGY_TR_GAIN_TYPE ); h.gain_constant = getf( SEGY_TR_INSTR_GAIN_CONST ); h.gain_initial = getf( SEGY_TR_INSTR_INIT_GAIN ); h.correlated = getf( SEGY_TR_CORRELATED ); h.sweep_freq_start = getf( SEGY_TR_SWEEP_FREQ_START ); h.sweep_freq_end = getf( SEGY_TR_SWEEP_FREQ_END ); h.sweep_length = getf( SEGY_TR_SWEEP_LENGTH ); h.sweep_type = getf( SEGY_TR_SWEEP_TYPE ); h.sweep_taperlen_start = getf( SEGY_TR_SWEEP_TAPERLEN_START ); h.sweep_taperlen_end = getf( SEGY_TR_SWEEP_TAPERLEN_END ); h.taper_type = getf( SEGY_TR_TAPER_TYPE ); h.alias_filt_freq = getf( SEGY_TR_ALIAS_FILT_FREQ ); h.alias_filt_slope = getf( SEGY_TR_ALIAS_FILT_SLOPE ); h.notch_filt_freq = getf( SEGY_TR_NOTCH_FILT_FREQ ); h.notch_filt_slope = getf( SEGY_TR_NOTCH_FILT_SLOPE ); h.low_cut_freq = getf( SEGY_TR_LOW_CUT_FREQ ); h.high_cut_freq = getf( SEGY_TR_HIGH_CUT_FREQ ); h.low_cut_slope = getf( SEGY_TR_LOW_CUT_SLOPE ); h.high_cut_slope = getf( SEGY_TR_HIGH_CUT_SLOPE ); h.year = getf( SEGY_TR_YEAR_DATA_REC ); h.day = getf( SEGY_TR_DAY_OF_YEAR ); h.hour = getf( SEGY_TR_HOUR_OF_DAY ); h.min = getf( SEGY_TR_MIN_OF_HOUR ); h.sec = getf( SEGY_TR_SEC_OF_MIN ); h.timecode = getf( SEGY_TR_TIME_BASE_CODE ); h.weighting_factor = getf( SEGY_TR_WEIGHTING_FAC ); h.geophone_group_roll1 = getf( SEGY_TR_GEOPHONE_GROUP_ROLL1 ); h.geophone_group_first = getf( SEGY_TR_GEOPHONE_GROUP_FIRST ); h.geophone_group_last = getf( SEGY_TR_GEOPHONE_GROUP_LAST ); h.gap_size = getf( SEGY_TR_GAP_SIZE ); h.over_travel = getf( SEGY_TR_OVER_TRAVEL ); h.cdp_x = getf( SEGY_TR_CDP_X ); h.cdp_y = getf( SEGY_TR_CDP_Y ); h.iline = getf( SEGY_TR_INLINE ); h.xline = getf( SEGY_TR_CROSSLINE ); h.shot_point = getf( SEGY_TR_SHOT_POINT ); h.shot_point_scalar = getf( SEGY_TR_SHOT_POINT_SCALAR ); h.unit = getf( SEGY_TR_MEASURE_UNIT ); h.transduction_mantissa = getf( SEGY_TR_TRANSDUCTION_MANT ); h.transduction_exponent = getf( SEGY_TR_TRANSDUCTION_EXP ); h.transduction_unit = getf( SEGY_TR_TRANSDUCTION_UNIT ); h.device_id = getf( SEGY_TR_DEVICE_ID ); h.scalar_trace_header = getf( SEGY_TR_SCALAR_TRACE_HEADER ); h.source_type = getf( SEGY_TR_SOURCE_TYPE ); h.source_energy_dir_mant = getf( SEGY_TR_SOURCE_ENERGY_DIR_MANT ); h.source_energy_dir_exp = getf( SEGY_TR_SOURCE_ENERGY_DIR_EXP ); h.source_measure_mant = getf( SEGY_TR_SOURCE_MEASURE_MANT ); h.source_measure_exp = getf( SEGY_TR_SOURCE_MEASURE_EXP ); h.source_measure_unit = getf( SEGY_TR_SOURCE_MEASURE_UNIT ); return h; } template< typename T > segyio::sorting volume_meta_fromfile< T >::sorting() const noexcept(true) { return this->sort; } template< typename T > int volume_meta_fromfile< T >::inlinecount() const noexcept(true) { return this->ilines; } template< typename T > int volume_meta_fromfile< T >::crosslinecount() const noexcept(true) { return this->xlines; } template< typename T > int volume_meta_fromfile< T >::offsetcount() const noexcept(true) { return this->offs; } template< typename Derived > void volume_meta_fromfile< Derived >::operator()( segy_file* fp, const config& cfg ) noexcept(false) { auto* self = static_cast< Derived* >( this ); const auto il = int(cfg.iline); const auto xl = int(cfg.xline); int sort = SEGY_UNKNOWN_SORTING; int err; err = segy_sorting( fp, il, xl, SEGY_TR_OFFSET, &sort, self->trace0(), self->tracesize() ); switch( err ) { case SEGY_OK: break; case SEGY_INVALID_FIELD: // TODO: figure out which one throw std::invalid_argument( "invalid il/xl/offset field" ); case SEGY_FSEEK_ERROR: throw errnomsg( "seek error while determining sorting" ); case SEGY_FREAD_ERROR: throw errnomsg( "read error while determining sorting" ); case SEGY_INVALID_SORTING: throw std::invalid_argument( "file is not sorted" ); default: throw unknown_error( err ); } const auto srt = segyio::sorting{ sort }; int ils, xls, ofs; err = segy_offsets( fp, il, xl, self->tracecount(), &ofs, self->trace0(), self->tracesize() ); switch( err ) { case SEGY_OK: break; case SEGY_FSEEK_ERROR: throw errnomsg( "seek error while counting offsets" ); case SEGY_FREAD_ERROR: throw errnomsg( "read error while counting offsets" ); default: throw unknown_error( err ); } err = segy_lines_count( fp, il, xl, sort, ofs, &ils, &xls, self->trace0(), self->tracesize() ); switch( err ) { case SEGY_OK: break; case SEGY_NOTFOUND: throw std::invalid_argument( "found only offsets in file" ); case SEGY_FSEEK_ERROR: throw errnomsg( "seek error while counting lines" ); case SEGY_FREAD_ERROR: throw errnomsg( "read error while counting lines" ); default: throw unknown_error( err ); } this->sort = srt; this->ilines = ils; this->xlines = xls; this->offs = ofs; } template< typename Derived > template< typename InputIt > InputIt trace_writer< Derived >::put( int i, InputIt in ) noexcept(false) { auto* self = static_cast< Derived* >( this ); auto* fp = self->escape(); self->consider( i ); static_assert( any_traits< Derived, writable, write_always >::value, "trace_writer needs a 'writable' trait" ); auto* raw = self->buffer(); const auto len = self->samplecount(); const auto format = int(self->format()); switch( format ) { case SEGY_IBM_FLOAT_4_BYTE: case SEGY_IEEE_FLOAT_4_BYTE: std::copy_n( in, len, reinterpret_cast< float* >( raw ) ); break; case SEGY_SIGNED_INTEGER_4_BYTE: std::copy_n( in, len, reinterpret_cast< std::int32_t* >( raw ) ); break; case SEGY_SIGNED_SHORT_2_BYTE: std::copy_n( in, len, reinterpret_cast< std::int16_t* >( raw ) ); break; case SEGY_SIGNED_CHAR_1_BYTE: std::copy_n( in, len, reinterpret_cast< std::int8_t* >( raw ) ); break; default: throw std::runtime_error( std::string("this->format is broken (was ") + self->format().description() + ")" ); } segy_from_native( format, len, self->buffer() ); auto err = segy_writetrace( fp, i, self->buffer(), self->trace0(), self->tracesize() ); switch( err ) { case SEGY_OK: break; case SEGY_FSEEK_ERROR: throw errnomsg( "unable to seek trace " + std::to_string(i) ); case SEGY_FWRITE_ERROR: throw errnomsg( "unable to write trace " + std::to_string(i) ); default: throw unknown_error( err ); } return in + len; } } #endif //SEGYIO_HPP segyio-1.8.3/cppcheck/0000775000372000037200000000000013407674361014217 5ustar travistravissegyio-1.8.3/cppcheck/suppressions.txt0000664000372000037200000000125013407674361017533 0ustar travistravispreprocessorErrorDirective:*pyconfig.h preprocessorErrorDirective:*Python.h // Ignore all warnings for external libraries *:*external/* // cppcheck struggles with the expression templates of catch, giving this error // for long == long comparisons compareBoolExpressionWithInt:*lib/test/segy.cpp // cppcheck gets very confused by fixtures, claiming members are unused, // so just ignore that warning unusedStructMember:*lib/test/segy.cpp // cppcheck struggles with some of the template code of the C++ front, // and syntax errors are not that interesting from a cppcheck point of view, // since the compiler handles them nicely syntaxError:*lib/experimental/segyio/segyio.hpp segyio-1.8.3/cppcheck/segyio.cfg0000664000372000037200000000343513407674361016204 0ustar travistravis false false false false false false segy_open segy_close segyio-1.8.3/License.md0000664000372000037200000001673113407674361014353 0ustar travistravis### GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. #### 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. #### 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. #### 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: - a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or - b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. #### 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: - a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. - b) Accompany the object code with a copy of the GNU GPL and this license document. #### 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: - a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. - b) Accompany the Combined Work with a copy of the GNU GPL and this license document. - c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. - d) Do one of the following: - 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. - 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. - e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) #### 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: - a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. - b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. #### 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. segyio-1.8.3/CMakeLists.txt0000664000372000037200000001041513407674361015200 0ustar travistraviscmake_minimum_required(VERSION 2.8.12) project(segyio) include(CheckFunctionExists) include(CheckIncludeFile) include(CTest) include(GNUInstallDirs) include(TestBigEndian) if (DEFINED ENV{SEGYIO_NO_GIT_VER}) set(SEGYIO_NO_GIT_VER CACHE BOOL "Ignore version from git" ON) endif () if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git AND NOT SEGYIO_NO_GIT_VER) find_program(git-bin git) execute_process(COMMAND ${git-bin} describe --tags OUTPUT_VARIABLE git-describe OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE describe-failure WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) if (NOT describe-failure) message(STATUS "Found version ${git-describe} from git") else () message(STATUS "No version from git - falling back to 0.0.0") set(git-describe 0.0.0) endif () string(REGEX REPLACE "^v" "" ver-describe "${git-describe}") unset(git-bin) elseif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/python/segyio/version.py) # tarball checkout - the version file should've been written when the # tarball was built file(READ python/segyio/version.py ver-describe) string(REGEX REPLACE "^version =" "" ver-describe ${ver-describe}) string(REGEX REPLACE "'" "" ver-describe ${ver-describe}) string(STRIP ${ver-describe} ver-describe) message(STATUS "Found version ${ver-describe} from segyio/version.py") else () set(ver-describe 0.0.0) message(STATUS "Could not find version, guessing ${ver-describe}") endif () string(REPLACE . ";" version-list ${ver-describe}) list(GET version-list 0 segyio-major) list(GET version-list 1 segyio-minor) list(GET version-list 2 segyio-patch) unset(version-list) # versions can always be overriden with -Dsegyio_MAJOR=N set(segyio_MAJOR ${segyio-major} CACHE STRING "Major version") set(segyio_MINOR ${segyio-minor} CACHE STRING "Minor version") set(segyio_PATCH ${segyio-patch} CACHE STRING "Patch") set(segyio_VERSION ${segyio_MAJOR}.${segyio_MINOR}.${segyio_PATCH}) message(STATUS "segyio version ${segyio_VERSION}") if (POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif () option(BUILD_SHARED_LIBS "Build language bindings shared" OFF) option(BUILD_BIN "Build applications" ON) option(BUILD_PYTHON "Build Python library" ON) option(REQUIRE_PYTHON "Fail cmake if python cannot be built" OFF) option(BUILD_MEX "Build Matlab mex files" OFF) option(BUILD_DOC "Build documentation" OFF) option(EXPERIMENTAL "Enable experimental features" OFF) check_include_file(getopt.h HAVE_GETOPT_H) check_include_file(sys/mman.h HAVE_SYS_MMAN_H) check_include_file(sys/stat.h HAVE_SYS_STAT_H) check_function_exists(getopt_long HAVE_GETOPT_LONG) if (HAVE_SYS_MMAN_H) list(APPEND mmap -DHAVE_MMAP) endif() if (HAVE_SYS_STAT_H) list(APPEND fstat -DHAVE_SYS_STAT_H) check_function_exists(_fstati64 HAVE_FSTATI64) if (HAVE_FSTATI64) list(APPEND fstat -DHAVE_FSTATI64) endif () check_function_exists(_ftelli64 HAVE_FTELLI64) if (HAVE_FTELLI64) list(APPEND fstat -DHAVE_FTELLI64) endif () else() message(FATAL_ERROR "Could not find sys/stat.h (fstat/ftelli)") endif() check_function_exists(ftello HAVE_FTELLO) if (HAVE_FTELLO) list(APPEND ftello -DHAVE_FTELLO) endif () if(NOT MSVC) set(m m) endif() if (NOT MSVC) # assuming gcc-style options set(c99 -std=c99) set(c++11 -std=c++11) # add warnings in debug mode list(APPEND warnings-c -Wall -Wextra -pedantic -Wformat-nonliteral -Wcast-align -Wpointer-arith -Wmissing-declarations -Wcast-qual -Wwrite-strings -Wchar-subscripts -Wredundant-decls ) else() list(APPEND warnings-c /W3 /wd4996) endif () test_big_endian(HOST_BIG_ENDIAN) # add documentation master target for other documentation sub targets to hook # into add_custom_target(doc ALL) set(testdata ${CMAKE_CURRENT_SOURCE_DIR}/test-data) add_subdirectory(external/catch2) add_subdirectory(lib) # language bindings add_subdirectory(mex) add_subdirectory(python) add_subdirectory(applications) add_subdirectory(man) segyio-1.8.3/.pyup.yml0000664000372000037200000000017313407674361014236 0ustar travistravis# autogenerated pyup.io config file # see https://pyup.io/docs/configuration/ for all available options update: insecure segyio-1.8.3/setup.cfg0000664000372000037200000000010513407674361014254 0ustar travistravis[aliases] test=pytest [tool:pytest] python_files = python/test/*.py segyio-1.8.3/python/0000775000372000037200000000000013407674361013760 5ustar travistravissegyio-1.8.3/python/segyio/0000775000372000037200000000000013407674361015257 5ustar travistravissegyio-1.8.3/python/segyio/tracesortingformat.py0000664000372000037200000000017513407674361021551 0ustar travistravisfrom . import Enum class TraceSortingFormat(Enum): UNKNOWN_SORTING = 0 CROSSLINE_SORTING = 1 INLINE_SORTING = 2 segyio-1.8.3/python/segyio/line.py0000664000372000037200000004116413407674361016566 0ustar travistravisimport collections import itertools try: from future_builtins import zip except ImportError: pass import numpy as np from .utils import castarray # in order to support [:end] syntax, we must make sure # start has a non-None value. lineno.indices() would set it # to 0, but we don't know if that's a reasonable value or # not. If start is None we set it to the first line def sanitize_slice(s, source): if all((s.start, s.stop, s.step)): return s start, stop, step = s.start, s.stop, s.step increasing = step is None or step > 0 if start is None: start = min(source) if increasing else max(source) if stop is None: stop = max(source) + 1 if increasing else min(source) - 1 return slice(start, stop, step) class Line(collections.Mapping): """ The Line implements the dict interface, with a fixed set of int_like keys, the line numbers/labels. Data is read lazily from disk, so iteration does not consume much memory, and are returned as numpy.ndarrays. It provides a convenient interface for reading data in a cartesian grid system, provided one exists and is detectable by segyio. Lines can be accessed individually or with slices, and writing is done via assignment. Note that accessing lines uses the line numbers, not their position, so if a files has lines [2400..2500], accessing line [0..100] will be an error. Note that since each line is returned as a numpy.ndarray, meaning accessing the intersections of the inline and crossline is 0-indexed - orthogonal labels are not preserved. Additionally, the line has a concept of offsets, which is useful when dealing with prestack files. Offsets are accessed via sub indexing, meaning iline[10, 4] will give you line 10 at offset 4. Please note that offset, like lines, are accessed via their labels, not their indices. If your file has the offsets [150, 250, 350, 450] and the lines [2400..2500], you can access the third offset with [2403, 350]. Please refer to the examples for more details. If no offset is specified, segyio will give you the first. Notes ----- .. versionadded:: 1.1 .. versionchanged:: 1.6 common dict operations (collections.Mapping) """ def __init__(self, filehandle, labels, length, stride, offsets, name): self.filehandle = filehandle.xfd self.lines = labels self.length = length self.stride = stride self.shape = (length, len(filehandle.samples)) self.dtype = filehandle.dtype # pre-compute all line beginnings from ._segyio import fread_trace0 self.heads = { label: fread_trace0(label, length, stride, len(offsets), labels, name) for label in labels } self.offsets = { x: i for i, x in enumerate(offsets) } self.default_offset = offsets[0] def ranges(self, index, offset): if not isinstance(index, slice): index = slice(index, index + 1) if not isinstance(offset, slice): offset = slice(offset, offset + 1) index = sanitize_slice(index, self.heads.keys()) offset = sanitize_slice(offset, self.offsets.keys()) irange = range(*index.indices(max(self.heads.keys()) + 1)) orange = range(*offset.indices(max(self.offsets.keys()) + 1)) irange = filter(self.heads.__contains__, irange) orange = filter(self.offsets.__contains__, orange) # offset-range is used in inner loops, so make it a list for # reusability. offsets are usually few, so no real punishment by using # non-generators here return irange, list(orange) def __getitem__(self, index): """line[i] or line[i, o] The line `i`, or the line `i` at a specific offset `o`. ``line[i]`` returns a numpy array, and changes to this array will *not* be reflected on disk. The `i` and `o` are *keys*, and should correspond to the line- and offset labels in your file, and in the `ilines`, `xlines`, and `offsets` attributes. Slices can contain lines and offsets not in the file, and like with list slicing, these are handled gracefully and ignored. When `i` or `o` is a slice, a generator of numpy arrays is returned. If the slice is defaulted (:), segyio knows enough about the structure to give you all of the respective labels. When both `i` and `o` are slices, only one generator is returned, and the lines are yielded offsets-first, roughly equivalent to the double for loop:: >>> for line in lines: ... for off in offsets: ... yield line[line, off] ... Parameters ---------- i : int or slice o : int or slice Returns ------- line : numpy.ndarray of dtype or generator of numpy.ndarray of dtype Raises ------ KeyError If `i` or `o` don't exist Notes ----- .. versionadded:: 1.1 Examples -------- Read an inline: >>> x = line[2400] Copy every inline into a list: >>> l = [numpy.copy(x) for x in iline[:]] Numpy operations on every other inline: >>> for line in line[::2]: ... line = line * 2 ... avg = np.average(line) Read lines up to 2430: >>> for line in line[:2430]: ... line.mean() Copy all lines at all offsets: >>> l = [numpy.copy(x) for x in line[:,:]] Copy all offsets of a line: >>> x = numpy.copy(iline[10,:]) Copy all lines at a fixed offset: >>> x = numpy.copy(iline[:, 120]) Copy every other line and offset: >>> map(numpy.copy, line[::2, ::2]) Copy all offsets [200, 250, 300, 350, ...] in the range [200, 800) for all lines [2420,2460): >>> l = [numpy.copy(x) for x in line[2420:2460, 200:800:50]] """ offset = self.default_offset try: index, offset = index except TypeError: pass # prioritise the code path that's potentially in loops externally try: head = self.heads[index] + self.offsets[offset] except TypeError: # index is either unhashable (because it's a slice), or offset is a # slice. pass else: return self.filehandle.getline(head, self.length, self.stride, len(self.offsets), np.empty(self.shape, dtype=self.dtype), ) # at this point, either offset or index is a slice (or proper # type-error), so we're definitely making a generator. make them both # slices to unify all code paths irange, orange = self.ranges(index, offset) def gen(): x = np.empty(self.shape, dtype=self.dtype) y = np.copy(x) # only fetch lines that exist. the slice can generate both offsets # and line numbers that don't exist, so filter out misses before # they happen for line in irange: for off in orange: head = self.heads[line] + self.offsets[off] self.filehandle.getline(head, self.length, self.stride, len(self.offsets), y, ) y, x = x, y yield x return gen() def __setitem__(self, index, val): """line[i] = val or line[i, o] = val Follows the same rules for indexing and slicing as ``line[i]``. In either case, if the `val` iterable is exhausted before the line(s), assignment stops with whatever is written so far. If `val` is longer than an individual line, it's essentially truncated. Parameters ---------- i : int or slice offset : int or slice val : array_like Raises ------ KeyError If `i` or `o` don't exist Notes ----- .. versionadded:: 1.1 Examples -------- Copy a full line: >>> line[2400] = other[2834] Copy first half of the inlines from g to f: >>> line[:] = other[:labels[len(labels) / 2]] Copy every other line consecutively: >>> line[:] = other[::2] Copy every third offset: >>> line[:,:] = other[:,::3] Copy a line into a set line and offset: >>> line[12, 200] = other[21] """ offset = self.default_offset try: index, offset = index except TypeError: pass try: head = self.heads[index] + self.offsets[offset] except TypeError: pass else: return self.filehandle.putline(head, self.length, self.stride, len(self.offsets), index, offset, castarray(val, dtype = self.dtype), ) irange, orange = self.ranges(index, offset) val = iter(val) for line in irange: for off in orange: head = self.heads[line] + self.offsets[off] try: self.filehandle.putline(head, self.length, self.stride, len(self.offsets), line, off, next(val), ) except StopIteration: return # can't rely on most collections.Mapping default implementations of # dict-like, because iter() does not yield keys for this class, it gives # the lines themselves. that violates some assumptions (but segyio's always # worked that way), and it's the more natural behaviour for segyio, so it's # acceptible. additionally, the default implementations would be very slow # and ineffective because they assume __getitem__ is sufficiently cheap, # but it isn't here since it involves a disk operation def __len__(self): """x.__len__() <==> len(x)""" return len(self.heads) def __iter__(self): """x.__iter__() <==> iter(x)""" return self[:] def __contains__(self, key): """x.__contains__(y) <==> y in x""" return key in self.heads def keys(self): """D.keys() -> a set-like object providing a view on D's keys""" return sorted(self.heads.keys()) def values(self): """D.values() -> generator of D's values""" return self[:] def items(self): """D.values() -> generator of D's (key,values), as 2-tuples""" return zip(self.keys(), self[:]) class HeaderLine(Line): """ The Line implements the dict interface, with a fixed set of int_like keys, the line numbers/labels. The values are iterables of Field objects. Notes ----- .. versionadded:: 1.1 .. versionchanged:: 1.6 common dict operations (collections.Mapping) """ # a lot of implementation details are shared between reading data traces # line-by-line and trace headers line-by-line, so (ab)use inheritance for # __len__, keys() etc., however, the __getitem__ is way different and is re-implemented def __init__(self, header, base, direction): super(HeaderLine, self).__init__(header.segy, base.lines, base.length, base.stride, sorted(base.offsets.keys()), 'header.' + direction, ) self.header = header def __getitem__(self, index): """line[i] or line[i, o] The line `i`, or the line `i` at a specific offset `o`. ``line[i]`` returns an iterable of `Field` objects, and changes to these *will* be reflected on disk. The `i` and `o` are *keys*, and should correspond to the line- and offset labels in your file, and in the `ilines`, `xlines`, and `offsets` attributes. Slices can contain lines and offsets not in the file, and like with list slicing, these are handled gracefully and ignored. When `i` or `o` is a slice, a generator of iterables of headers are returned. When both `i` and `o` are slices, one generator is returned for the product `i` and `o`, and the lines are yielded offsets-first, roughly equivalent to the double for loop:: >>> for line in lines: ... for off in offsets: ... yield line[line, off] ... Parameters ---------- i : int or slice o : int or slice Returns ------- line : iterable of Field or generator of iterator of Field Raises ------ KeyError If `i` or `o` don't exist Notes ----- .. versionadded:: 1.1 """ offset = self.default_offset try: index, offset = index except TypeError: pass try: start = self.heads[index] + self.offsets[offset] except TypeError: # index is either unhashable (because it's a slice), or offset is a # slice. pass else: step = self.stride * len(self.offsets) stop = start + step * self.length return self.header[start:stop:step] def gen(): irange, orange = self.ranges(index, offset) for line in irange: for off in orange: yield self[line, off] return gen() def __setitem__(self, index, val): """line[i] = val or line[i, o] = val Follows the same rules for indexing and slicing as ``line[i]``. If `i` is an int, and `val` is a dict or Field, that value is replicated and assigned to every trace header in the line, otherwise it's treated as an iterable, and each trace in the line is assigned the ``next()`` yielded value. If `i` or `o` is a slice, `val` must be an iterable. In either case, if the `val` iterable is exhausted before the line(s), assignment stops with whatever is written so far. Parameters ---------- i : int or slice offset : int or slice val : dict_like or iterable of dict_like Raises ------ KeyError If `i` or `o` don't exist Notes ----- .. versionadded:: 1.1 Examples -------- Rename the iline 3 to 4: >>> line[3] = { TraceField.INLINE_3D: 4 } >>> # please note that rewriting the header won't update the >>> # file's interpretation of the file until you reload it, so >>> # the new iline 4 will be considered iline 3 until the file >>> # is reloaded Set offset line 3 offset 3 to 5: >>> line[3, 3] = { TraceField.offset: 5 } """ offset = self.default_offset try: index, offset = index except TypeError: pass try: start = self.heads[index] + self.offsets[offset] except TypeError: pass else: try: if hasattr(val, 'keys'): val = itertools.repeat(val) except TypeError: # already an iterable pass step = self.stride * len(self.offsets) stop = start + step * self.length self.header[start:stop:step] = val return irange, orange = self.ranges(index, offset) val = iter(val) for line in irange: for off in orange: try: self[line, off] = next(val) except StopIteration: return segyio-1.8.3/python/segyio/segyio.cpp0000664000372000037200000014070113407674361017265 0ustar travistravis#if defined(_DEBUG) && defined(_MSC_VER) # define _CRT_NOFORCE_MAINFEST 1 # undef _DEBUG # include # include # define _DEBUG 1 #else # include # include #endif #include "segyio/segy.h" #include #include #include #include #if PY_MAJOR_VERSION >= 3 #define IS_PY3K #endif namespace { std::string segy_errstr( int err ) { std::stringstream ss; switch( err ) { case SEGY_OK: return "segyio.ok"; case SEGY_FOPEN_ERROR: return "segyio.fopen"; case SEGY_FSEEK_ERROR: return "segyio.fseek"; case SEGY_FREAD_ERROR: return "segyio.fread"; case SEGY_FWRITE_ERROR: return "segyio.fwrite"; case SEGY_INVALID_FIELD: return "segyio.invalid.field"; case SEGY_INVALID_SORTING: return "segyio.invalid.sorting"; case SEGY_MISSING_LINE_INDEX: return "segyio.missing.lineindex"; case SEGY_INVALID_OFFSETS: return "segyio.invalid.offsets"; case SEGY_TRACE_SIZE_MISMATCH: return "segyio.trace.size.mismatch"; case SEGY_INVALID_ARGS: return "segyio.invalid.args"; case SEGY_MMAP_ERROR: return "segyio.mmap.error"; case SEGY_MMAP_INVALID: return "segyio.mmap.invalid"; case SEGY_READONLY: return "segyio.readonly"; case SEGY_NOTFOUND: return "segyio.notfound"; default: ss << "code " << err << ""; return ss.str(); } } template< typename T1 > PyObject* TypeError( const char* msg, T1 t1 ) { return PyErr_Format( PyExc_TypeError, msg, t1 ); } PyObject* ValueError( const char* msg ) { PyErr_SetString( PyExc_ValueError, msg ); return NULL; } template< typename T1 > PyObject* ValueError( const char* msg, T1 t1 ) { return PyErr_Format( PyExc_ValueError, msg, t1 ); } template< typename T1, typename T2 > PyObject* ValueError( const char* msg, T1 t1, T2 t2 ) { return PyErr_Format( PyExc_ValueError, msg, t1, t2 ); } template< typename T1, typename T2 > PyObject* IndexError( const char* msg, T1 t1, T2 t2 ) { return PyErr_Format( PyExc_IndexError, msg, t1, t2 ); } template< typename T1, typename T2, typename T3 > PyObject* IndexError( const char* msg, T1 t1, T2 t2, T3 t3 ) { return PyErr_Format( PyExc_IndexError, msg, t1, t2, t3 ); } PyObject* BufferError( const char* msg ) { PyErr_SetString( PyExc_BufferError, msg ); return NULL; } PyObject* RuntimeError( const char* msg ) { PyErr_SetString( PyExc_RuntimeError, msg ); return NULL; } PyObject* RuntimeError( int err ) { const std::string msg = "uncaught exception: " + segy_errstr( err ); return RuntimeError( msg.c_str() ); } PyObject* IOErrno() { return PyErr_SetFromErrno( PyExc_IOError ); } PyObject* IOError( const char* msg ) { PyErr_SetString( PyExc_IOError, msg ); return NULL; } template< typename T1, typename T2 > PyObject* IOError( const char* msg, T1 t1, T2 t2 ) { return PyErr_Format( PyExc_IOError, msg, t1, t2 ); } template< typename T1 > PyObject* IOError( const char* msg, T1 t1 ) { return PyErr_Format( PyExc_IOError, msg, t1 ); } template< typename T1 > PyObject* KeyError( const char* msg, T1 t1 ) { return PyErr_Format( PyExc_KeyError, msg, t1 ); } template< typename T1, typename T2 > PyObject* KeyError( const char* msg, T1 t1, T2 t2 ) { return PyErr_Format( PyExc_KeyError, msg, t1, t2 ); } PyObject* Error( int err ) { /* * a default error handler. The fseek errors are sufficiently described * with errno, and all cases that raise fwrite and fread errors get * sufficient context from stack trace to be generalised with a better * message. * * Anything else falls through to a generic RuntimeError "uncaught * exception" */ switch( err ) { case SEGY_FSEEK_ERROR: return IOErrno(); case SEGY_FWRITE_ERROR: // fallthrough case SEGY_FREAD_ERROR: return IOError( "I/O operation failed, " "likely corrupted file" ); case SEGY_READONLY: return IOError( "file not open for writing. " "open with 'r+'" ); default: return RuntimeError( err ); } } struct autofd { operator segy_file*() const; operator bool() const; void swap( autofd& other ); void close(); segy_file* fd; }; autofd::operator segy_file*() const { if( this->fd ) return this->fd; IOError( "I/O operation on closed file" ); return NULL; } autofd::operator bool() const { return this->fd; } void autofd::swap( autofd& other ) { std::swap( this->fd, other.fd ); } void autofd::close() { if( this->fd ) segy_close( this->fd ); this->fd = NULL; } struct segyiofd { PyObject_HEAD autofd fd; long trace0; int trace_bsize; int tracecount; int samplecount; int format; int elemsize; }; struct buffer_guard { /* automate Py_buffer handling. * * the python documentation does not mention any exception guarantees when * PyArg_ParseTuple, so assume that whenever the function fails, the buffer * object is either zero'd or untouched. That means checking if a * PyBuffer_Release should be called boils down to checking if underlying * buffer is a nullptr or not */ buffer_guard() { Py_buffer b = {}; this->buffer = b; } explicit buffer_guard( const Py_buffer& b ) : buffer( b ) {} buffer_guard( PyObject* o, int flags = PyBUF_CONTIG_RO ) { Py_buffer b = {}; this->buffer = b; if( !PyObject_CheckBuffer( o ) ) { TypeError( "'%s' does not expose buffer interface", o->ob_type->tp_name ); return; } const int cont = PyBUF_C_CONTIGUOUS; if( PyObject_GetBuffer( o, &this->buffer, flags | cont ) == 0 ) return; if( (flags & PyBUF_WRITABLE) == PyBUF_WRITABLE ) BufferError( "buffer must be contiguous and writable" ); else BufferError( "buffer must be contiguous and readable" ); } ~buffer_guard() { if( *this ) PyBuffer_Release( &this->buffer ); } operator bool() const { return this->buffer.buf; } Py_ssize_t len() const { return this->buffer.len; } Py_buffer* operator&() { return &this->buffer; } template< typename T > T* buf() const { return static_cast< T* >( this->buffer.buf ); } char* buf() const { return this->buf< char >(); } Py_buffer buffer; }; namespace fd { int init( segyiofd* self, PyObject* args, PyObject* kwargs ) { char* filename = NULL; char* mode = NULL; int endian = 0; if( !PyArg_ParseTuple( args, "ssi", &filename, &mode, &endian ) ) return -1; if( std::strlen( mode ) == 0 ) { ValueError( "mode string must be non-empty" ); return -1; } if( std::strlen( mode ) > 3 ) { ValueError( "invalid mode string '%s', good strings are %s", mode, "'r' (read-only) and 'r+' (read-write)" ); return -1; } struct unique : public autofd { explicit unique( segy_file* p ) { this->fd = p; } ~unique() { this->close(); } } fd( segy_open( filename, mode ) ); if( !fd && !strstr( "rb" "wb" "ab" "r+b" "w+b" "a+b", mode ) ) { ValueError( "invalid mode string '%s', good strings are %s", mode, "'r' (read-only) and 'r+' (read-write)" ); return -1; } if( !fd ) { IOErrno(); return -1; } switch( endian ) { case 0: case SEGY_LSB: case SEGY_MSB: break; default: ValueError( "internal: unexpected endianness, was %d", endian ); return -1; } int err = segy_set_format( fd, endian ); if( err ) { ValueError( "internal: error setting endianness, was %d", endian ); return -1; } /* * init can be called multiple times, which is treated as opening a new * file on the same object. That means the previous file handle must be * properly closed before the new file is set */ self->fd.swap( fd ); return 0; } PyObject* segyopen( segyiofd* self ) { segy_file* fp = self->fd; if( !fp ) return NULL; int tracecount = 0; char binary[ SEGY_BINARY_HEADER_SIZE ] = {}; int err = segy_binheader( fp, binary ); if( err ) return Error( err ); const long trace0 = segy_trace0( binary ); const int samplecount = segy_samples( binary ); const int format = segy_format( binary ); int trace_bsize = segy_trsize( format, samplecount ); /* fall back to assuming 4-byte ibm float if the format field is rubbish */ if( trace_bsize < 0 ) trace_bsize = segy_trace_bsize( samplecount ); /* * if set_format errors, it's because the format-field in the binary header * is 0 or some other garbage. if so, assume the file is 4-byte ibm float */ segy_set_format( fp, format ); int elemsize = 4; switch( format ) { case SEGY_IBM_FLOAT_4_BYTE: elemsize = 4; break; case SEGY_SIGNED_INTEGER_4_BYTE: elemsize = 4; break; case SEGY_SIGNED_SHORT_2_BYTE: elemsize = 2; break; case SEGY_FIXED_POINT_WITH_GAIN_4_BYTE: elemsize = 4; break; case SEGY_IEEE_FLOAT_4_BYTE: elemsize = 4; break; case SEGY_SIGNED_CHAR_1_BYTE: elemsize = 1; break; case SEGY_NOT_IN_USE_1: case SEGY_NOT_IN_USE_2: default: break; } err = segy_traces( fp, &tracecount, trace0, trace_bsize ); switch( err ) { case SEGY_OK: break; case SEGY_FSEEK_ERROR: return IOErrno(); case SEGY_INVALID_ARGS: return RuntimeError( "unable to count traces, " "no data traces past headers" ); case SEGY_TRACE_SIZE_MISMATCH: return RuntimeError( "trace count inconsistent with file size, " "trace lengths possibly of non-uniform" ); default: return Error( err ); } self->trace0 = trace0; self->trace_bsize = trace_bsize; self->format = format; self->elemsize = elemsize; self->samplecount = samplecount; self->tracecount = tracecount; Py_INCREF( self ); return (PyObject*) self; } PyObject* segycreate( segyiofd* self, PyObject* args, PyObject* kwargs ) { segy_file* fp = self->fd; if( !fp ) return NULL; int samples; int tracecount; int ext_headers = 0; int format = SEGY_IBM_FLOAT_4_BYTE; // https://mail.python.org/pipermail/python-dev/2006-February/060689.html // python3 fixes the non-constness of the kwlist arg in // ParseTupleAndKeywords, since C++ really prefers writing string literals // as const // // Remove the const_cast when python2 support is dropped static const char* kwlist[] = { "samples", "tracecount", "format", "ext_headers", NULL, }; if( !PyArg_ParseTupleAndKeywords( args, kwargs, "ii|ii", const_cast< char** >(kwlist), &samples, &tracecount, &format, &ext_headers ) ) return NULL; if( samples <= 0 ) return ValueError( "expected samples > 0" ); if( tracecount <= 0 ) return ValueError( "expected tracecount > 0" ); if( ext_headers < 0 ) return ValueError( "ext_headers must be non-negative" ); switch( format ) { case SEGY_IBM_FLOAT_4_BYTE: case SEGY_SIGNED_INTEGER_4_BYTE: case SEGY_SIGNED_SHORT_2_BYTE: case SEGY_FIXED_POINT_WITH_GAIN_4_BYTE: case SEGY_IEEE_FLOAT_4_BYTE: case SEGY_SIGNED_CHAR_1_BYTE: break; default: return ValueError( "unknown format identifier" ); } int elemsize = 4; switch( format ) { case SEGY_IBM_FLOAT_4_BYTE: case SEGY_SIGNED_INTEGER_4_BYTE: case SEGY_FIXED_POINT_WITH_GAIN_4_BYTE: case SEGY_IEEE_FLOAT_4_BYTE: elemsize = 4; break; case SEGY_SIGNED_SHORT_2_BYTE: elemsize = 2; break; case SEGY_SIGNED_CHAR_1_BYTE: elemsize = 1; break; default: assert(false || "format should already be checked" ); break; } self->trace0 = SEGY_TEXT_HEADER_SIZE + SEGY_BINARY_HEADER_SIZE + SEGY_TEXT_HEADER_SIZE * ext_headers; self->trace_bsize = segy_trsize( format, samples ); self->format = format; self->elemsize = elemsize; self->samplecount = samples; self->tracecount = tracecount; Py_INCREF( self ); return (PyObject*) self; } PyObject* suopen( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; if( !PyArg_ParseTuple( args, "" ) ) return NULL; int err = segy_set_format( fp, SEGY_IEEE_FLOAT_4_BYTE ); if( err ) return RuntimeError( "internal: unable to set type to IEEE float " ); char header[ SEGY_TRACE_HEADER_SIZE ] = {}; err = segy_traceheader( fp, 0, header, 0, 0 ); if( err ) return IOError( "unable to read first trace header in SU file" ); int32_t f; segy_get_field( header, SEGY_TR_SAMPLE_COUNT, &f ); const long trace0 = 0; const int samplecount = f; const int elemsize = sizeof( float ); int trace_bsize = elemsize * samplecount; int tracecount; err = segy_traces( fp, &tracecount, trace0, trace_bsize ); switch( err ) { case SEGY_OK: break; case SEGY_FSEEK_ERROR: return IOErrno(); case SEGY_INVALID_ARGS: return RuntimeError( "unable to count traces, " "no data traces past headers" ); case SEGY_TRACE_SIZE_MISMATCH: return RuntimeError( "trace count inconsistent with file size, " "trace lengths possibly of non-uniform" ); default: return Error( err ); } self->trace0 = trace0; self->trace_bsize = trace_bsize; self->format = SEGY_IEEE_FLOAT_4_BYTE; self->elemsize = elemsize; self->samplecount = samplecount; self->tracecount = tracecount; Py_INCREF( self ); return (PyObject*) self; } void dealloc( segyiofd* self ) { self->fd.close(); Py_TYPE( self )->tp_free( (PyObject*) self ); } PyObject* close( segyiofd* self ) { /* multiple close() is a no-op */ if( !self->fd ) return Py_BuildValue( "" ); errno = 0; self->fd.close(); if( errno ) return IOErrno(); return Py_BuildValue( "" ); } PyObject* flush( segyiofd* self ) { segy_file* fp = self->fd; if( !fp ) return NULL; errno = 0; segy_flush( self->fd, false ); if( errno ) return IOErrno(); return Py_BuildValue( "" ); } PyObject* mmap( segyiofd* self ) { segy_file* fp = self->fd; if( !fp ) return NULL; const int err = segy_mmap( fp ); if( err != SEGY_OK ) Py_RETURN_FALSE; Py_RETURN_TRUE; } /* * No C++11, so no std::vector::data. single-alloc automatic heap buffer, * without resize */ struct heapbuffer { explicit heapbuffer( int sz ) : ptr( new( std::nothrow ) char[ sz ] ) { if( !this->ptr ) { PyErr_SetString( PyExc_MemoryError, "unable to alloc buffer" ); return; } std::memset( this->ptr, 0, sz ); } ~heapbuffer() { delete[] this->ptr; } operator char*() { return this->ptr; } operator const char*() const { return this->ptr; } char* ptr; private: heapbuffer( const heapbuffer& ); }; PyObject* gettext( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; int index = 0; if( !PyArg_ParseTuple( args, "i", &index ) ) return NULL; heapbuffer buffer( segy_textheader_size() ); if( !buffer ) return NULL; const int err = index == 0 ? segy_read_textheader( fp, buffer ) : segy_read_ext_textheader( fp, index - 1, buffer ); if( err ) return Error( err ); const size_t len = std::strlen( buffer ); return PyByteArray_FromStringAndSize( buffer, len ); } PyObject* puttext( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; int index; buffer_guard buffer; if( !PyArg_ParseTuple( args, "is*", &index, &buffer ) ) return NULL; int size = std::min( int(buffer.len()), SEGY_TEXT_HEADER_SIZE ); heapbuffer buf( SEGY_TEXT_HEADER_SIZE ); if( !buf ) return NULL; const char* src = buffer.buf< const char >(); std::copy( src, src + size, buf.ptr ); const int err = segy_write_textheader( fp, index, buf ); if( err ) return Error( err ); return Py_BuildValue( "" ); } PyObject* getbin( segyiofd* self ) { segy_file* fp = self->fd; if( !fp ) return NULL; char buffer[ SEGY_BINARY_HEADER_SIZE ] = {}; const int err = segy_binheader( fp, buffer ); if( err ) return Error( err ); return PyByteArray_FromStringAndSize( buffer, sizeof( buffer ) ); } PyObject* putbin( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; buffer_guard buffer; if( !PyArg_ParseTuple(args, "s*", &buffer ) ) return NULL; if( buffer.len() < SEGY_BINARY_HEADER_SIZE ) return ValueError( "internal: binary buffer too small, " "expected %i, was %zd", SEGY_BINARY_HEADER_SIZE, buffer.len() ); const int err = segy_write_binheader( fp, buffer.buf< const char >() ); if( err == SEGY_INVALID_ARGS ) return IOError( "file not open for writing. open with 'r+'" ); if( err ) return Error( err ); return Py_BuildValue( "" ); } PyObject* getth( segyiofd* self, PyObject *args ) { segy_file* fp = self->fd; if( !fp ) return NULL; int traceno; PyObject* bufferobj; if( !PyArg_ParseTuple( args, "iO", &traceno, &bufferobj ) ) return NULL; buffer_guard buffer( bufferobj, PyBUF_CONTIG ); if( !buffer ) return NULL; if( buffer.len() < SEGY_TRACE_HEADER_SIZE ) return ValueError( "internal: trace header buffer too small, " "expected %i, was %zd", SEGY_TRACE_HEADER_SIZE, buffer.len() ); int err = segy_traceheader( fp, traceno, buffer.buf(), self->trace0, self->trace_bsize ); switch( err ) { case SEGY_OK: Py_INCREF( bufferobj ); return bufferobj; case SEGY_FREAD_ERROR: return IOError( "I/O operation failed on trace header %d", traceno ); default: return Error( err ); } } PyObject* putth( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; int traceno; buffer_guard buf; if( !PyArg_ParseTuple( args, "is*", &traceno, &buf ) ) return NULL; if( buf.len() < SEGY_TRACE_HEADER_SIZE ) return ValueError( "internal: trace header buffer too small, " "expected %i, was %zd", SEGY_TRACE_HEADER_SIZE, buf.len() ); const char* buffer = buf.buf< const char >(); const int err = segy_write_traceheader( fp, traceno, buffer, self->trace0, self->trace_bsize ); switch( err ) { case SEGY_OK: return Py_BuildValue( "" ); case SEGY_FWRITE_ERROR: return IOError( "I/O operation failed on trace header %d", traceno ); default: return Error( err ); } } PyObject* field_forall( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; PyObject* bufferobj; int start, stop, step; int field; if( !PyArg_ParseTuple( args, "Oiiii", &bufferobj, &start, &stop, &step, &field ) ) return NULL; if( step == 0 ) return ValueError( "slice step cannot be zero" ); buffer_guard buffer( bufferobj, PyBUF_CONTIG ); if( !buffer ) return NULL; const int err = segy_field_forall( fp, field, start, stop, step, buffer.buf< int >(), self->trace0, self->trace_bsize ); if( err ) return Error( err ); Py_INCREF( bufferobj ); return bufferobj; } PyObject* field_foreach( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; PyObject* bufferobj; buffer_guard indices; int field; if( !PyArg_ParseTuple( args, "Os*i", &bufferobj, &indices, &field ) ) return NULL; buffer_guard bufout( bufferobj, PyBUF_CONTIG ); if( !bufout ) return NULL; if( bufout.len() != indices.len() ) return ValueError( "internal: array size mismatch " "(output %zd, indices %zd)", bufout.len(), indices.len() ); const int* ind = indices.buf< const int >(); int* out = bufout.buf< int >(); Py_ssize_t len = bufout.len() / sizeof(int); int err = 0; for( int i = 0; err == 0 && i < len; ++i ) { err = segy_field_forall( fp, field, ind[ i ], ind[ i ] + 1, 1, out + i, self->trace0, self->trace_bsize ); } if( err ) return Error( err ); Py_INCREF( bufferobj ); return bufferobj; } PyObject* metrics( segyiofd* self ) { static const int text = SEGY_TEXT_HEADER_SIZE; static const int bin = SEGY_BINARY_HEADER_SIZE; const int ext = (self->trace0 - (text + bin)) / text; return Py_BuildValue( "{s:i, s:l, s:i, s:i, s:i, s:i}", "tracecount", self->tracecount, "trace0", self->trace0, "trace_bsize", self->trace_bsize, "samplecount", self->samplecount, "format", self->format, "ext_headers", ext ); } struct metrics_errmsg { int il, xl, of; PyObject* operator()( int err ) const { switch( err ) { case SEGY_INVALID_FIELD: return IndexError( "invalid iline, (%i), xline (%i), " "or offset (%i) field", il, xl, of ); case SEGY_INVALID_SORTING: return RuntimeError( "unable to find sorting." ); default: return Error( err ); } } }; PyObject* cube_metrics( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; int il; int xl; if( !PyArg_ParseTuple( args, "ii", &il, &xl ) ) return NULL; metrics_errmsg errmsg = { il, xl, SEGY_TR_OFFSET }; int sorting = -1; int err = segy_sorting( fp, il, xl, SEGY_TR_OFFSET, &sorting, self->trace0, self->trace_bsize ); if( err ) return errmsg( err ); int offset_count = -1; err = segy_offsets( fp, il, xl, self->tracecount, &offset_count, self->trace0, self->trace_bsize ); if( err ) return errmsg( err ); int xl_count = 0; int il_count = 0; err = segy_lines_count( fp, il, xl, sorting, offset_count, &il_count, &xl_count, self->trace0, self->trace_bsize ); if( err == SEGY_NOTFOUND ) return ValueError( "could not parse geometry, " "open with strict=False" ); if( err ) return errmsg( err ); return Py_BuildValue( "{s:i, s:i, s:i, s:i, s:i, s:i, s:i}", "sorting", sorting, "iline_field", il, "xline_field", xl, "offset_field", 37, "offset_count", offset_count, "iline_count", il_count, "xline_count", xl_count ); } long getitem( PyObject* dict, const char* key ) { return PyLong_AsLong( PyDict_GetItemString( dict, key ) ); } PyObject* indices( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; PyObject* metrics; buffer_guard iline_out; buffer_guard xline_out; buffer_guard offset_out; if( !PyArg_ParseTuple( args, "O!w*w*w*", &PyDict_Type, &metrics, &iline_out, &xline_out, &offset_out ) ) return NULL; const int iline_count = getitem( metrics, "iline_count" ); const int xline_count = getitem( metrics, "xline_count" ); const int offset_count = getitem( metrics, "offset_count" ); if( iline_out.len() < Py_ssize_t(iline_count * sizeof( int )) ) return ValueError( "internal: inline indices buffer too small, " "expected %i, was %zd", iline_count, iline_out.len() ); if( xline_out.len() < Py_ssize_t(xline_count * sizeof( int )) ) return ValueError( "internal: crossline indices buffer too small, " "expected %i, was %zd", xline_count, xline_out.len() ); if( offset_out.len() < Py_ssize_t(offset_count * sizeof( int )) ) return ValueError( "internal: offset indices buffer too small, " "expected %i, was %zd", offset_count, offset_out.len() ); const int il_field = getitem( metrics, "iline_field" ); const int xl_field = getitem( metrics, "xline_field" ); const int offset_field = getitem( metrics, "offset_field" ); const int sorting = getitem( metrics, "sorting" ); if( PyErr_Occurred() ) return NULL; metrics_errmsg errmsg = { il_field, xl_field, SEGY_TR_OFFSET }; int err = segy_inline_indices( fp, il_field, sorting, iline_count, xline_count, offset_count, iline_out.buf< int >(), self->trace0, self->trace_bsize ); if( err ) return errmsg( err ); err = segy_crossline_indices( fp, xl_field, sorting, iline_count, xline_count, offset_count, xline_out.buf< int >(), self->trace0, self->trace_bsize ); if( err ) return errmsg( err ); err = segy_offset_indices( fp, offset_field, offset_count, offset_out.buf< int >(), self->trace0, self->trace_bsize ); if( err ) return errmsg( err ); return Py_BuildValue( "" ); } PyObject* gettr( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; PyObject* bufferobj; int start, length, step; if( !PyArg_ParseTuple( args, "Oiii", &bufferobj, &start, &step, &length ) ) return NULL; buffer_guard buffer( bufferobj, PyBUF_CONTIG ); if( !buffer) return NULL; const int samples = self->samplecount; const int skip = samples * self->elemsize; const long long bufsize = (long long) length * samples; const long trace0 = self->trace0; const int trace_bsize = self->trace_bsize; if( buffer.len() < bufsize ) return ValueError( "internal: data trace buffer too small, " "expected %zi, was %zd", bufsize, buffer.len() ); int err = 0; int i = 0; char* buf = buffer.buf(); for( ; err == 0 && i < length; ++i, buf += skip ) { err = segy_readtrace( fp, start + (i * step), buf, trace0, trace_bsize ); } if( err == SEGY_FREAD_ERROR ) return IOError( "I/O operation failed on data trace %d", i ); if( err ) return Error( err ); segy_to_native( self->format, bufsize, buffer.buf() ); Py_INCREF( bufferobj ); return bufferobj; } PyObject* puttr( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; int traceno; char* buffer; int buflen; if( !PyArg_ParseTuple( args, "is#", &traceno, &buffer, &buflen ) ) return NULL; if( self->trace_bsize > buflen ) return ValueError("trace too short: expected %d bytes, got %d", self->trace_bsize, buflen ); segy_from_native( self->format, self->samplecount, buffer ); int err = segy_writetrace( fp, traceno, buffer, self->trace0, self->trace_bsize ); segy_to_native( self->format, self->samplecount, buffer ); switch( err ) { case SEGY_OK: return Py_BuildValue(""); case SEGY_FREAD_ERROR: return IOError( "I/O operation failed on data trace %d", traceno ); default: return Error( err ); } } PyObject* getline( segyiofd* self, PyObject* args) { segy_file* fp = self->fd; if( !fp ) return NULL; int line_trace0; int line_length; int stride; int offsets; PyObject* bufferobj; if( !PyArg_ParseTuple( args, "iiiiO", &line_trace0, &line_length, &stride, &offsets, &bufferobj ) ) return NULL; buffer_guard buffer( bufferobj, PyBUF_CONTIG ); if( !buffer ) return NULL; int err = segy_read_line( fp, line_trace0, line_length, stride, offsets, buffer.buf(), self->trace0, self->trace_bsize); if( err ) return Error( err ); segy_to_native( self->format, self->samplecount * line_length, buffer.buf() ); Py_INCREF( bufferobj ); return bufferobj; } PyObject* putline( segyiofd* self, PyObject* args) { segy_file* fp = self->fd; if( !fp ) return NULL; int line_trace0; int line_length; int stride; int offsets; int index; int offset; PyObject* val; if( !PyArg_ParseTuple( args, "iiiiiiO", &line_trace0, &line_length, &stride, &offsets, &index, &offset, &val ) ) return NULL; buffer_guard buffer( val, PyBUF_CONTIG ); if( self->trace_bsize * line_length > buffer.len() ) return ValueError("line too short: expected %d elements, got %zd", self->samplecount * line_length, buffer.len() / self->elemsize ); const int elems = line_length * self->samplecount; segy_from_native( self->format, elems, buffer.buf() ); int err = segy_write_line( fp, line_trace0, line_length, stride, offsets, buffer.buf(), self->trace0, self->trace_bsize ); segy_to_native( self->format, elems, buffer.buf() ); switch( err ) { case SEGY_OK: return Py_BuildValue(""); case SEGY_FWRITE_ERROR: return IOError( "I/O operation failed on line %d, offset %d", index, offset ); default: return Error( err ); } } PyObject* getdepth( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; int depth; int count; int offsets; PyObject* bufferobj; if( !PyArg_ParseTuple( args, "iiiO", &depth, &count, &offsets, &bufferobj ) ) return NULL; buffer_guard buffer( bufferobj, PyBUF_CONTIG ); if( !buffer ) return NULL; int traceno = 0; int err = 0; char* buf = buffer.buf(); const int skip = self->elemsize; const long trace0 = self->trace0; const int trace_bsize = self->trace_bsize; for( ; err == 0 && traceno < count; ++traceno, buf += skip ) { err = segy_readsubtr( fp, traceno * offsets, depth, depth + 1, 1, buf, NULL, trace0, trace_bsize); } if( err == SEGY_FREAD_ERROR ) return IOError( "I/O operation failed on data trace %d at depth %d", traceno, depth ); if( err ) return Error( err ); segy_to_native( self->format, count, buffer.buf() ); Py_INCREF( bufferobj ); return bufferobj; } PyObject* putdepth( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; int depth; int count; int offsets; PyObject* val; if( !PyArg_ParseTuple( args, "iiiO", &depth, &count, &offsets, &val ) ) return NULL; buffer_guard buffer( val, PyBUF_CONTIG ); if( !buffer ) return NULL; if( count * self->elemsize > buffer.len() ) return ValueError("slice too short: expected %d elements, got %zd", count, buffer.len() / self->elemsize ); int traceno = 0; int err = 0; const char* buf = buffer.buf(); const int skip = self->elemsize; const long trace0 = self->trace0; const int trace_bsize = self->trace_bsize; segy_from_native( self->format, count, buffer.buf() ); for( ; err == 0 && traceno < count; ++traceno, buf += skip ) { err = segy_writesubtr( fp, traceno * offsets, depth, depth + 1, 1, buf, NULL, trace0, trace_bsize ); } segy_to_native( self->format, count, buffer.buf() ); if( err == SEGY_FREAD_ERROR ) return IOError( "I/O operation failed on data trace %d at depth %d", traceno, depth ); if( err ) return Error( err ); return Py_BuildValue( "" ); } PyObject* getdt( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; float fallback; if( !PyArg_ParseTuple(args, "f", &fallback ) ) return NULL; float dt; int err = segy_sample_interval( fp, fallback, &dt ); if( err == SEGY_OK ) return PyFloat_FromDouble( dt ); if( err != SEGY_FREAD_ERROR && err != SEGY_FSEEK_ERROR ) return Error( err ); /* * Figure out if the problem is reading the trace header * or the binary header */ char buffer[ SEGY_BINARY_HEADER_SIZE ]; err = segy_binheader( fp, buffer ); if( err ) return IOError( "I/O operation failed on binary header, " "likely corrupted file" ); err = segy_traceheader( fp, 0, buffer, self->trace0, self->trace_bsize ); if( err == SEGY_FREAD_ERROR ) return IOError( "I/O operation failed on trace header 0, " "likely corrupted file" ); return Error( err ); } PyObject* rotation( segyiofd* self, PyObject* args ) { segy_file* fp = self->fd; if( !fp ) return NULL; int line_length; int stride; int offsets; buffer_guard linenos; if( !PyArg_ParseTuple( args, "iiis*", &line_length, &stride, &offsets, &linenos ) ) return NULL; float rotation; int err = segy_rotation_cw( fp, line_length, stride, offsets, linenos.buf< const int >(), linenos.len() / sizeof( int ), &rotation, self->trace0, self->trace_bsize ); if( err ) return Error( err ); return PyFloat_FromDouble( rotation ); } PyMethodDef methods [] = { { "segyopen", (PyCFunction) fd::segyopen, METH_NOARGS, "Open file." }, { "segymake", (PyCFunction) fd::segycreate, METH_VARARGS | METH_KEYWORDS, "Create file." }, { "suopen", (PyCFunction) fd::suopen, METH_VARARGS, "Open SU file." }, { "close", (PyCFunction) fd::close, METH_VARARGS, "Close file." }, { "flush", (PyCFunction) fd::flush, METH_VARARGS, "Flush file." }, { "mmap", (PyCFunction) fd::mmap, METH_NOARGS, "mmap file." }, { "gettext", (PyCFunction) fd::gettext, METH_VARARGS, "Get text header." }, { "puttext", (PyCFunction) fd::puttext, METH_VARARGS, "Put text header." }, { "getbin", (PyCFunction) fd::getbin, METH_VARARGS, "Get binary header." }, { "putbin", (PyCFunction) fd::putbin, METH_VARARGS, "Put binary header." }, { "getth", (PyCFunction) fd::getth, METH_VARARGS, "Get trace header." }, { "putth", (PyCFunction) fd::putth, METH_VARARGS, "Put trace header." }, { "field_forall", (PyCFunction) fd::field_forall, METH_VARARGS, "Field for-all." }, { "field_foreach", (PyCFunction) fd::field_foreach, METH_VARARGS, "Field for-each." }, { "gettr", (PyCFunction) fd::gettr, METH_VARARGS, "Get trace." }, { "puttr", (PyCFunction) fd::puttr, METH_VARARGS, "Put trace." }, { "getline", (PyCFunction) fd::getline, METH_VARARGS, "Get line." }, { "putline", (PyCFunction) fd::putline, METH_VARARGS, "Put line." }, { "getdepth", (PyCFunction) fd::getdepth, METH_VARARGS, "Get depth." }, { "putdepth", (PyCFunction) fd::putdepth, METH_VARARGS, "Put depth." }, { "getdt", (PyCFunction) fd::getdt, METH_VARARGS, "Get sample interval (dt)." }, { "rotation", (PyCFunction) fd::rotation, METH_VARARGS, "Get clockwise rotation." }, { "metrics", (PyCFunction) fd::metrics, METH_NOARGS, "Metrics." }, { "cube_metrics", (PyCFunction) fd::cube_metrics, METH_VARARGS, "Cube metrics." }, { "indices", (PyCFunction) fd::indices, METH_VARARGS, "Indices." }, { NULL } }; } PyTypeObject Segyiofd = { PyVarObject_HEAD_INIT( NULL, 0 ) "_segyio.segyfd", /* name */ sizeof( segyiofd ), /* basic size */ 0, /* tp_itemsize */ (destructor)fd::dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ "segyio file descriptor", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ fd::methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)fd::init, /* tp_init */ }; PyObject* binsize( PyObject* ) { return PyLong_FromLong( segy_binheader_size() ); } PyObject* thsize( PyObject* ) { return PyLong_FromLong( SEGY_TRACE_HEADER_SIZE ); } PyObject* textsize(PyObject* ) { return PyLong_FromLong( SEGY_TEXT_HEADER_SIZE ); } PyObject* trbsize( PyObject*, PyObject* args ) { int sample_count; if( !PyArg_ParseTuple( args, "i", &sample_count ) ) return NULL; return PyLong_FromLong( segy_trace_bsize( sample_count ) ); } PyObject* getfield( PyObject*, PyObject *args ) { buffer_guard buffer; int field; if( !PyArg_ParseTuple( args, "s*i", &buffer, &field ) ) return NULL; if( buffer.len() != SEGY_BINARY_HEADER_SIZE && buffer.len() != SEGY_TRACE_HEADER_SIZE ) return BufferError( "buffer too small" ); int value = 0; int err = buffer.len() == segy_binheader_size() ? segy_get_bfield( buffer.buf< const char >(), field, &value ) : segy_get_field( buffer.buf< const char >(), field, &value ) ; switch( err ) { case SEGY_OK: return PyLong_FromLong( value ); case SEGY_INVALID_FIELD: return KeyError( "No such field %d", field ); default: return Error( err ); } } PyObject* putfield( PyObject*, PyObject *args ) { buffer_guard buffer; int field; int value; if( !PyArg_ParseTuple( args, "w*ii", &buffer, &field, &value ) ) return NULL; if( buffer.len() != SEGY_BINARY_HEADER_SIZE && buffer.len() != SEGY_TRACE_HEADER_SIZE ) return BufferError( "buffer too small" ); int err = buffer.len() == segy_binheader_size() ? segy_set_bfield( buffer.buf< char >(), field, value ) : segy_set_field( buffer.buf< char >(), field, value ) ; switch( err ) { case SEGY_OK: return PyLong_FromLong( value ); case SEGY_INVALID_FIELD: return KeyError( "No such field %d", field ); default: return Error( err ); } } PyObject* line_metrics( PyObject*, PyObject *args) { SEGY_SORTING sorting; int trace_count; int inline_count; int crossline_count; int offset_count; if( !PyArg_ParseTuple( args, "iiiii", &sorting, &trace_count, &inline_count, &crossline_count, &offset_count ) ) return NULL; int iline_length = segy_inline_length( crossline_count ); int xline_length = segy_crossline_length( inline_count ); int iline_stride = 0; int err = segy_inline_stride( sorting, inline_count, &iline_stride ); // only check first call since the only error that can occur is // SEGY_INVALID_SORTING if( err == SEGY_INVALID_SORTING ) return ValueError( "internal: invalid sorting." ); if( err ) return Error( err ); int xline_stride; segy_crossline_stride( sorting, crossline_count, &xline_stride ); return Py_BuildValue( "{s:i, s:i, s:i, s:i}", "xline_length", xline_length, "xline_stride", xline_stride, "iline_length", iline_length, "iline_stride", iline_stride ); } PyObject* fread_trace0( PyObject* , PyObject* args ) { int lineno; int other_line_length; int stride; int offsets; int* indices; int indiceslen; char* linetype; if( !PyArg_ParseTuple( args, "iiiis#s", &lineno, &other_line_length, &stride, &offsets, &indices, &indiceslen, &linetype ) ) return NULL; int trace_no = 0; int err = segy_line_trace0( lineno, other_line_length, stride, offsets, indices, indiceslen / sizeof( int ), &trace_no ); if( err == SEGY_MISSING_LINE_INDEX ) return KeyError( "no such %s %d", linetype, lineno ); if( err ) return Error( err ); return PyLong_FromLong( trace_no ); } PyObject* format( PyObject* , PyObject* args ) { PyObject *out; int format; if( !PyArg_ParseTuple( args, "Oi", &out, &format ) ) return NULL; buffer_guard buffer( out, PyBUF_CONTIG ); const int len = buffer.len() / sizeof( float ); segy_to_native( format, len, buffer.buf() ); Py_INCREF( out ); return out; } PyMethodDef SegyMethods[] = { { "binsize", (PyCFunction) binsize, METH_NOARGS, "Size of the binary header." }, { "thsize", (PyCFunction) thsize, METH_NOARGS, "Size of the trace header." }, { "textsize", (PyCFunction) textsize, METH_NOARGS, "Size of the text header." }, { "trace_bsize", (PyCFunction) trbsize, METH_VARARGS, "Size of a trace (in bytes)." }, { "getfield", (PyCFunction) getfield, METH_VARARGS, "Get a header field." }, { "putfield", (PyCFunction) putfield, METH_VARARGS, "Put a header field." }, { "line_metrics", (PyCFunction) line_metrics, METH_VARARGS, "Find the length and stride of lines." }, { "fread_trace0", (PyCFunction) fread_trace0, METH_VARARGS, "Find trace0 of a line." }, { "native", (PyCFunction) format, METH_VARARGS, "Convert to native float." }, { NULL } }; } /* module initialization */ #ifdef IS_PY3K static struct PyModuleDef segyio_module = { PyModuleDef_HEAD_INIT, "_segyio", /* name of module */ NULL, /* module documentation, may be NULL */ -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ SegyMethods }; PyMODINIT_FUNC PyInit__segyio(void) { Segyiofd.tp_new = PyType_GenericNew; if( PyType_Ready( &Segyiofd ) < 0 ) return NULL; PyObject* m = PyModule_Create(&segyio_module); if( !m ) return NULL; Py_INCREF( &Segyiofd ); PyModule_AddObject( m, "segyiofd", (PyObject*)&Segyiofd ); return m; } #else PyMODINIT_FUNC init_segyio(void) { Segyiofd.tp_new = PyType_GenericNew; if( PyType_Ready( &Segyiofd ) < 0 ) return; PyObject* m = Py_InitModule("_segyio", SegyMethods); Py_INCREF( &Segyiofd ); PyModule_AddObject( m, "segyiofd", (PyObject*)&Segyiofd ); } #endif segyio-1.8.3/python/segyio/tools.py0000664000372000037200000005412313407674361016776 0ustar travistravisimport segyio from . import TraceField from . import TraceSortingFormat from . import SegySampleFormat import numpy as np import textwrap def dt(f, fallback_dt=4000.0): """Delta-time Infer a ``dt``, the sample rate, from the file. If none is found, use the fallback. Parameters ---------- f : segyio.SegyFile fallback_dt : float delta-time to fall back to, in microseconds Returns ------- dt : float Notes ----- .. versionadded:: 1.1 """ return f.xfd.getdt(fallback_dt) def sample_indexes(segyfile, t0=0.0, dt_override=None): """ Creates a list of values representing the samples in a trace at depth or time. The list starts at *t0* and is incremented with am*dt* for the number of samples. If a *dt_override* is not provided it will try to find a *dt* in the file. Parameters ---------- segyfile : segyio.SegyFile t0 : float initial sample, or delay-recording-time dt_override : float or None Returns ------- samples : array_like of float Notes ----- .. versionadded:: 1.1 """ if dt_override is None: dt_override = dt(segyfile) return [t0 + t * dt_override for t in range(len(segyfile.samples))] def create_text_header(lines): """Format textual header Create a "correct" SEG-Y textual header. Every line will be prefixed with C## and there are 40 lines. The input must be a dictionary with the line number[1-40] as a key. The value for each key should be up to 76 character long string. Parameters ---------- lines : dict `lines` dictionary with fields: - ``no`` : line number (`int`) - ``line`` : line (`str`) Returns ------- text : str """ rows = [] for line_no in range(1, 41): line = "" if line_no in lines: line = lines[line_no] row = "C{0:>2} {1:76}".format(line_no, line) rows.append(row) rows = ''.join(rows) return rows def wrap(s, width=80): """ Formats the text input with newlines given the user specified width for each line. Parameters ---------- s : str width : int Returns ------- text : str Notes ----- .. versionadded:: 1.1 """ return '\n'.join(textwrap.wrap(str(s), width=width)) def native(data, format = segyio.SegySampleFormat.IBM_FLOAT_4_BYTE, copy = True): """Convert numpy array to native float Converts a numpy array from raw segy trace data to native floats. Works for numpy ndarrays. Parameters ---------- data : numpy.ndarray format : int or segyio.SegySampleFormat copy : bool If True, convert on a copy, and leave the input array unmodified Returns ------- data : numpy.ndarray Notes ----- .. versionadded:: 1.1 Examples -------- Convert mmap'd trace to native float: >>> d = np.memmap('file.sgy', offset = 3600, dtype = np.uintc) >>> samples = 1500 >>> trace = segyio.tools.native(d[240:240+samples]) """ data = data.view( dtype = np.single ) if copy: data = np.copy( data ) format = int(segyio.SegySampleFormat(format)) return segyio._segyio.native(data, format) def collect(itr): """Collect traces or lines into one ndarray Eagerly copy a series of traces, lines or depths into one numpy ndarray. If collecting traces or fast-direction over a post-stacked file, reshaping the resulting array is equivalent to calling ``segyio.tools.cube``. Parameters ---------- itr : iterable of numpy.ndarray Returns ------- data : numpy.ndarray Notes ----- .. versionadded:: 1.1 Examples -------- collect-cube identity: >>> f = segyio.open('post-stack.sgy') >>> x = segyio.tools.collect(f.traces[:]) >>> x = x.reshape((len(f.ilines), len(f.xlines), f.samples)) >>> numpy.all(x == segyio.tools.cube(f)) """ return np.stack([np.copy(x) for x in itr]) def cube(f): """Read a full cube from a file Takes an open segy file (created with segyio.open) or a file name. If the file is a prestack file, the cube returned has the dimensions ``(fast, slow, offset, sample)``. If it is post-stack (only the one offset), the dimensions are normalised to ``(fast, slow, sample)`` Parameters ---------- f : str or segyio.SegyFile Returns ------- cube : numpy.ndarray Notes ----- .. versionadded:: 1.1 """ if not isinstance(f, segyio.SegyFile): with segyio.open(f) as fl: return cube(fl) ilsort = f.sorting == segyio.TraceSortingFormat.INLINE_SORTING fast = f.ilines if ilsort else f.xlines slow = f.xlines if ilsort else f.ilines fast, slow, offs = len(fast), len(slow), len(f.offsets) smps = len(f.samples) dims = (fast, slow, smps) if offs == 1 else (fast, slow, offs, smps) return f.trace.raw[:].reshape(dims) def rotation(f, line = 'fast'): """ Find rotation of the survey Find the clock-wise rotation and origin of `line` as ``(rot, cdpx, cdpy)`` The clock-wise rotation is defined as the angle in radians between line given by the first and last trace of the first line and the axis that gives increasing CDP-Y, in the direction that gives increasing CDP-X. By default, the first line is the 'fast' direction, which is inlines if the file is inline sorted, and crossline if it's crossline sorted. Parameters ---------- f : SegyFile line : { 'fast', 'slow', 'iline', 'xline' } Returns ------- rotation : float cdpx : int cdpy : int Notes ----- .. versionadded:: 1.2 """ if f.unstructured: raise ValueError("Rotation requires a structured file") lines = { 'fast': f.fast, 'slow': f.slow, 'iline': f.iline, 'xline': f.xline, } if line not in lines: error = "Unknown line {}".format(line) solution = "Must be any of: {}".format(' '.join(lines.keys())) raise ValueError('{} {}'.format(error, solution)) l = lines[line] origin = f.header[0][segyio.su.cdpx, segyio.su.cdpy] cdpx, cdpy = origin[segyio.su.cdpx], origin[segyio.su.cdpy] rot = f.xfd.rotation( len(l), l.stride, len(f.offsets), np.fromiter(l.keys(), dtype = np.intc) ) return rot, cdpx, cdpy def metadata(f): """Get survey structural properties and metadata Create a description object that, when passed to ``segyio.create()``, would create a new file with the same structure, dimensions, and metadata as ``f``. Takes an open segy file (created with segyio.open) or a file name. Parameters ---------- f : str or segyio.SegyFile Returns ------- spec : segyio.spec Notes ----- .. versionadded:: 1.4 """ if not isinstance(f, segyio.SegyFile): with segyio.open(f) as fl: return metadata(fl) spec = segyio.spec() spec.iline = f._il spec.xline = f._xl spec.samples = f.samples spec.format = f.format spec.ilines = f.ilines spec.xlines = f.xlines spec.offsets = f.offsets spec.sorting = f.sorting spec.tracecount = f.tracecount spec.ext_headers = f.ext_headers spec.endian = f.endian return spec def resample(f, rate = None, delay = None, micro = False, trace = True, binary = True): """Resample a file Resample all data traces, and update the file handle to reflect the new sample rate. No actual samples (data traces) are modified, only the header fields and interpretation. By default, the rate and the delay are in millseconds - if you need higher resolution, passing micro=True interprets rate as microseconds (as it is represented in the file). Delay is always milliseconds. By default, both the global binary header and the trace headers are updated to reflect this. If preserving either the trace header interval field or the binary header interval field is important, pass trace=False and binary=False respectively, to not have that field updated. This only apply to sample rates - the recording delay is only found in trace headers and will be written unconditionally, if delay is not None. .. warning:: This function requires an open file handle and is **DESTRUCTIVE**. It will modify the file, and if an exception is raised then partial writes might have happened and the file might be corrupted. This function assumes all traces have uniform delays and frequencies. Parameters ---------- f : SegyFile rate : int delay : int micro : bool if True, interpret rate as microseconds trace : bool Update the trace header if True binary : bool Update the binary header if True Notes ----- .. versionadded:: 1.4 """ if rate is not None: if not micro: rate *= 1000 if binary: f.bin[segyio.su.hdt] = rate if trace: f.header = { segyio.su.dt: rate} if delay is not None: f.header = { segyio.su.delrt: delay } t0 = delay if delay is not None else f.samples[0] rate = rate / 1000 if rate is not None else f.samples[1] - f.samples[0] f._samples = (np.arange(len(f.samples)) * rate) + t0 return f def from_array(filename, data, iline=189, xline=193, format=SegySampleFormat.IBM_FLOAT_4_BYTE, dt=4000, delrt=0): """ Create a new SEGY file from an n-dimentional array Create an structured SEGY file with defaulted headers from a 2-, 3- or 4-dimensional array. from_array() recognizes the shape of the array and calls the correct from_arrayxD() function. I.e. calling this with a 2-dimensional array produces the exact same result as calling from_array2D() directly. Parameters ---------- filename : string-like Path to new file data : 2-,3- or 4-dimensional array-like iline : int or segyio.TraceField Inline number field in the trace headers. Defaults to 189 as per the SEG-Y rev1 specification xline : int or segyio.TraceField Crossline number field in the trace headers. Defaults to 193 as per the SEG-Y rev1 specification format : int or segyio.SegySampleFormat Sample format field in the trace header. Defaults to IBM float 4 byte dt : int-like sample interval delrt : int-like Notes ----- .. versionadded:: 1.8 Examples -------- Create a file from a 3D array, open it and read an iline: >>> segyio.tools.from_array(path, array3d) >>> segyio.open(path, mode) as f: ... iline = f.iline[0] ... """ data = np.asarray(data) dimensions = len(data.shape) if dimensions not in range(2,5): problem = "Expected 2, 3 or 4 dimensions, {} was given".format(dimensions) raise ValueError(problem) if dimensions == 2: return from_array2D(filename, data, iline, xline, format, dt, delrt) if dimensions == 3: return from_array3D(filename, data, iline, xline, format, dt, delrt) if dimensions == 4: return from_array4D(filename, data, iline, xline, format, dt, delrt) def from_array2D(filename, data, iline=189, xline=193, format=SegySampleFormat.IBM_FLOAT_4_BYTE, dt=4000, delrt=0): """ Create a new SEGY file from a 2D array Create an structured SEGY file with defaulted headers from a 2-dimensional array. The file is inline-sorted and structured as a slice, i.e. it has one iline and the xlinecount equals the tracecount. The tracecount and samplecount are inferred from the size of the array. Structure-defining fields in the binary header and in the traceheaders are set accordingly. Such fields include, but are not limited to iline, xline and offset. The file also contains a defaulted textual header. The 2 dimensional array is interpreted as:: samples -------------------- trace 0 | s0 | s1 | ... | sn | -------------------- trace 1 | s0 | s1 | ... | sn | -------------------- . . -------------------- trace n | s0 | s1 | ... | sn | -------------------- traces = [0, len(axis(0)] samples = [0, len(axis(1)] Parameters ---------- filename : string-like Path to new file data : 2-dimensional array-like iline : int or segyio.TraceField Inline number field in the trace headers. Defaults to 189 as per the SEG-Y rev1 specification xline : int or segyio.TraceField Crossline number field in the trace headers. Defaults to 193 as per the SEG-Y rev1 specification format : int or segyio.SegySampleFormat Sample format field in the trace header. Defaults to IBM float 4 byte dt : int-like sample interval delrt : int-like Notes ----- .. versionadded:: 1.8 Examples -------- Create a file from a 2D array, open it and read a trace: >>> segyio.tools.from_array2D(path, array2d) >>> segyio.open(path, mode, strict=False) as f: ... tr = f.trace[0] """ dt = int(dt) delrt = int(delrt) data = np.asarray(data) dimensions = len(data.shape) if dimensions != 2: problem = "Expected 3 dimensions, {} was given".format(dimensions) raise ValueError(problem) tracecount = np.size(data, 0) samplecount = np.size(data, 1) spec = segyio.spec() spec.iline = iline spec.xline = xline spec.format = format spec.ilines = [1] spec.xlines = list(range(1, tracecount + 1)) spec.samples = list(range(samplecount)) spec.sorting = TraceSortingFormat.INLINE_SORTING with segyio.create(filename, spec) as f: f.iline[1] = data for tr in range(f.tracecount): f.header[tr] = { TraceField.TraceNumber : tr, TraceField.CDP_TRACE : tr, TraceField.offset : spec.offsets[0], TraceField.INLINE_3D : spec.ilines[0], TraceField.CROSSLINE_3D : spec.xlines[tr], TraceField.TRACE_SAMPLE_COUNT : samplecount, TraceField.TRACE_SAMPLE_INTERVAL : dt, TraceField.DelayRecordingTime : delrt } f.bin.update( tsort=TraceSortingFormat.INLINE_SORTING, hdt=dt, dto=dt ) def from_array3D(filename, data, iline=189, xline=193, format=SegySampleFormat.IBM_FLOAT_4_BYTE, dt=4000, delrt=0): """ Create a new SEGY file from a 3D array Create an structured SEGY file with defaulted headers from a 3-dimensional array. The file is inline-sorted. ilines, xlines and samples are inferred from the array. Structure-defining fields in the binary header and in the traceheaders are set accordingly. Such fields include, but are not limited to iline, xline and offset. The file also contains a defaulted textual header. The 3-dimensional array is interpreted as:: xl0 xl1 xl2 ----------------- / | tr0 | tr1 | tr2 | il0 ----------------- | / | tr3 | tr4 | tr5 | il1 ----------------- | / | tr6 | tr7 | tr8 | il2 ----------------- | / / / / n-samples ------------------ ilines = [1, len(axis(0) + 1] xlines = [1, len(axis(1) + 1] samples = [0, len(axis(2)] Parameters ---------- filename : string-like Path to new file data : 3-dimensional array-like iline : int or segyio.TraceField Inline number field in the trace headers. Defaults to 189 as per the SEG-Y rev1 specification xline : int or segyio.TraceField Crossline number field in the trace headers. Defaults to 193 as per the SEG-Y rev1 specification format : int or segyio.SegySampleFormat Sample format field in the trace header. Defaults to IBM float 4 byte dt : int-like sample interval delrt : int-like Notes ----- .. versionadded:: 1.8 Examples -------- Create a file from a 3D array, open it and read an iline: >>> segyio.tools.from_array3D(path, array3d) >>> segyio.open(path, mode) as f: ... iline = f.iline[0] ... """ dt = int(dt) delrt = int(delrt) data = np.asarray(data) dimensions = len(data.shape) if dimensions != 3: problem = "Expected 3 dimensions, {} was given".format(dimensions) raise ValueError(problem) ilinecount = np.size(data, 0) xlinecount = np.size(data, 1) samplecount = np.size(data, 2) spec = segyio.spec() spec.iline = iline spec.xline = xline spec.format = format spec.ilines = list(range(1, ilinecount + 1)) spec.xlines = list(range(1, xlinecount + 1)) spec.samples = list(range(samplecount)) spec.sorting = TraceSortingFormat.INLINE_SORTING with segyio.create(filename, spec) as f: for index, ilno in enumerate(spec.ilines): iline = np.concatenate([data[index,xl,:] for xl in range(xlinecount)]) iline = iline.reshape((xlinecount, samplecount)) print(ilno) f.iline[ilno] = iline f.header.iline[ilno] = { TraceField.INLINE_3D: ilno } for xlno in spec.xlines: f.header.xline[xlno] = { TraceField.CROSSLINE_3D: xlno} for tr in range(f.tracecount): f.header[tr] = { TraceField.TraceNumber : tr, TraceField.CDP_TRACE : tr, TraceField.offset : spec.offsets[0], TraceField.TRACE_SAMPLE_COUNT : samplecount, TraceField.TRACE_SAMPLE_INTERVAL : dt, TraceField.DelayRecordingTime : delrt } f.bin.update( tsort=TraceSortingFormat.INLINE_SORTING, hdt=dt, dto=dt ) def from_array4D(filename, data, iline=189, xline=193, format=SegySampleFormat.IBM_FLOAT_4_BYTE, dt=4000, delrt=0): """ Create a new SEGY file from a 4D array Create an structured SEGY file with defaulted headers from a 4-dimensional array. The file is inline-sorted. ilines, xlines, offsets and samples are inferred from the array. Structure-defining fields in the binary header and in the traceheaders are set accordingly. Such fields include, but are not limited to iline, xline and offset. The file also contains a defaulted textual header. The 4D array is interpreted: ilines = [1, len(axis(0) + 1] xlines = [1, len(axis(1) + 1] offsets = [1, len(axis(2) + 1] samples = [0, len(axis(3)] Parameters ---------- filename : string-like Path to new file data : 4-dimensional array-like iline : int or segyio.TraceField Inline number field in the trace headers. Defaults to 189 as per the SEG-Y rev1 specification xline : int or segyio.TraceField Crossline number field in the trace headers. Defaults to 193 as per the SEG-Y rev1 specification format : int or segyio.SegySampleFormat Sample format field in the trace header. Defaults to IBM float 4 byte dt : int-like sample interval delrt : int-like Notes ----- .. versionadded:: 1.8 Examples -------- Create a file from a 3D array, open it and read an iline: >>> segyio.tools.create_from_array4D(path, array4d) >>> segyio.open(path, mode) as f: ... iline = f.iline[0] ... """ dt = int(dt) delrt = int(delrt) data = np.asarray(data) dimensions = len(data.shape) if dimensions != 4: problem = "Expected 4 dimensions, {} was given".format(dimensions) raise ValueError(problem) ilinecount = np.size(data, 0) xlinecount = np.size(data, 1) samplecount = np.size(data, 3) offsetcount = np.size(data, 2) spec = segyio.spec() spec.iline = iline spec.xline = xline spec.format = format spec.ilines = list(range(1, ilinecount + 1)) spec.xlines = list(range(1, xlinecount + 1)) spec.offsets = list(range(1, offsetcount + 1)) spec.samples = list(range(samplecount)) spec.sorting = TraceSortingFormat.INLINE_SORTING with segyio.create(filename, spec) as f: for ilindex, ilno in enumerate(spec.ilines): for offindex, offno in enumerate(spec.offsets): iline = np.concatenate([data[ilindex, xl, offindex, :] for xl in range(xlinecount)]) iline = iline.reshape((xlinecount, samplecount)) f.iline[ilno, offno] = iline f.header.iline[ilno, offno] = { TraceField.INLINE_3D : ilno, TraceField.offset : offno } for xlno in spec.xlines: for offno in spec.offsets: f.header.xline[xlno, offno] = {TraceField.CROSSLINE_3D: xlno} for tr in range(f.tracecount): f.header[tr] = { TraceField.TraceNumber : tr, TraceField.CDP_TRACE : tr, TraceField.TRACE_SAMPLE_COUNT : samplecount, TraceField.TRACE_SAMPLE_INTERVAL : dt, TraceField.DelayRecordingTime : delrt } f.bin.update( tsort=TraceSortingFormat.INLINE_SORTING, hdt=dt, dto=dt ) segyio-1.8.3/python/segyio/open.py0000664000372000037200000001261213407674361016574 0ustar travistravisimport numpy import segyio def infer_geometry(f, metrics, iline, xline, strict): try: cube_metrics = f.xfd.cube_metrics(iline, xline) f._sorting = cube_metrics['sorting'] iline_count = cube_metrics['iline_count'] xline_count = cube_metrics['xline_count'] offset_count = cube_metrics['offset_count'] metrics.update(cube_metrics) ilines = numpy.zeros(iline_count, dtype=numpy.intc) xlines = numpy.zeros(xline_count, dtype=numpy.intc) offsets = numpy.zeros(offset_count, dtype=numpy.intc) f.xfd.indices(metrics, ilines, xlines, offsets) f.interpret(ilines, xlines, offsets, f._sorting) except: if not strict: f._ilines = None f._xlines = None f._offsets = None else: f.close() raise return f def open(filename, mode="r", iline = 189, xline = 193, strict = True, ignore_geometry = False, endian = 'big'): """Open a segy file. Opens a segy file and tries to figure out its sorting, inline numbers, crossline numbers, and offsets, and enables reading and writing to this file in a simple manner. For reading, the access mode `r` is preferred. All write operations will raise an exception. For writing, the mode `r+` is preferred (as `rw` would truncate the file). Any mode with `w` will raise an error. The modes used are standard C file modes; please refer to that documentation for a complete reference. Open should be used together with python's ``with`` statement. Please refer to the examples. When the ``with`` statement is used the file will automatically be closed when the routine completes or an exception is raised. By default, segyio tries to open in ``strict`` mode. This means the file will be assumed to represent a geometry with consistent inline, crosslines and offsets. If strict is False, segyio will still try to establish a geometry, but it won't abort if it fails. When in non-strict mode is opened, geometry-dependent modes such as iline will raise an error. If ``ignore_geometry=True``, segyio will *not* try to build iline/xline or other geometry related structures, which leads to faster opens. This is essentially the same as using ``strict=False`` on a file that has no geometry. Parameters ---------- filename : str Path to file to open mode : {'r', 'r+'} File access mode, read-only ('r', default) or read-write ('r+') iline : int or segyio.TraceField Inline number field in the trace headers. Defaults to 189 as per the SEG-Y rev1 specification xline : int or segyio.TraceField Crossline number field in the trace headers. Defaults to 193 as per the SEG-Y rev1 specification strict : bool, optional Abort if a geometry cannot be inferred. Defaults to True. ignore_geometry : bool, optional Opt out on building geometry information, useful for e.g. shot organised files. Defaults to False. endian : {'big', 'msb', 'little', 'lsb'} File endianness, big/msb (default) or little/lsb Returns ------- file : segyio.SegyFile An open segyio file handle Raises ------ ValueError If the mode string contains 'w', as it would truncate the file Notes ----- .. versionadded:: 1.1 .. versionchanged:: 1.8 endian argument When a file is opened non-strict, only raw traces access is allowed, and using modes such as ``iline`` raise an error. Examples -------- Open a file in read-only mode: >>> with segyio.open(path, "r") as f: ... print(f.ilines) ... [1, 2, 3, 4, 5] Open a file in read-write mode: >>> with segyio.open(path, "r+") as f: ... f.trace = np.arange(100) Open two files at once: >>> with segyio.open(path) as src, segyio.open(path, "r+") as dst: ... dst.trace = src.trace # copy all traces from src to dst Open a file little-endian file: >>> with segyio.open(path, endian = 'little') as f: ... f.trace[0] """ if 'w' in mode: problem = 'w in mode would truncate the file' solution = 'use r+ to open in read-write' raise ValueError(', '.join((problem, solution))) endians = { 'little': 256, # (1 << 8) 'lsb': 256, 'big': 0, 'msb': 0, } if endian not in endians: problem = 'unknown endianness {}, expected one of: ' opts = ' '.join(endians.keys()) raise ValueError(problem.format(endian) + opts) from . import _segyio fd = _segyio.segyiofd(str(filename), mode, endians[endian]) fd.segyopen() metrics = fd.metrics() f = segyio.SegyFile(fd, filename = str(filename), mode = mode, iline = iline, xline = xline, endian = endian, ) try: dt = segyio.tools.dt(f, fallback_dt = 4000.0) / 1000.0 t0 = f.header[0][segyio.TraceField.DelayRecordingTime] samples = metrics['samplecount'] f._samples = (numpy.arange(samples) * dt) + t0 except: f.close() raise if ignore_geometry: return f return infer_geometry(f, metrics, iline, xline, strict) segyio-1.8.3/python/segyio/binfield.py0000664000372000037200000000407013407674361017406 0ustar travistravisfrom . import Enum class BinField(Enum): """Trace header field enumerator See also ------- segyio.su : Seismic unix aliases for header fields """ JobID = 3201 LineNumber = 3205 ReelNumber = 3209 Traces = 3213 AuxTraces = 3215 Interval = 3217 IntervalOriginal = 3219 Samples = 3221 SamplesOriginal = 3223 Format = 3225 EnsembleFold = 3227 SortingCode = 3229 VerticalSum = 3231 SweepFrequencyStart = 3233 SweepFrequencyEnd = 3235 SweepLength = 3237 Sweep = 3239 SweepChannel = 3241 SweepTaperStart = 3243 SweepTaperEnd = 3245 Taper = 3247 CorrelatedTraces = 3249 BinaryGainRecovery = 3251 AmplitudeRecovery = 3253 MeasurementSystem = 3255 ImpulseSignalPolarity = 3257 VibratoryPolarity = 3259 Unassigned1 = 3261 SEGYRevision = 3501 TraceFlag = 3503 ExtendedHeaders = 3505 Unassigned2 = 3507 keys = { 'JobID' : 3201, 'LineNumber' : 3205, 'ReelNumber' : 3209, 'Traces' : 3213, 'AuxTraces' : 3215, 'Interval' : 3217, 'IntervalOriginal' : 3219, 'Samples' : 3221, 'SamplesOriginal' : 3223, 'Format' : 3225, 'EnsembleFold' : 3227, 'SortingCode' : 3229, 'VerticalSum' : 3231, 'SweepFrequencyStart' : 3233, 'SweepFrequencyEnd' : 3235, 'SweepLength' : 3237, 'Sweep' : 3239, 'SweepChannel' : 3241, 'SweepTaperStart' : 3243, 'SweepTaperEnd' : 3245, 'Taper' : 3247, 'CorrelatedTraces' : 3249, 'BinaryGainRecovery' : 3251, 'AmplitudeRecovery' : 3253, 'MeasurementSystem' : 3255, 'ImpulseSignalPolarity' : 3257, 'VibratoryPolarity' : 3259, 'Unassigned1' : 3261, 'SEGYRevision' : 3501, 'TraceFlag' : 3503, 'ExtendedHeaders' : 3505, 'Unassigned2' : 3507, } segyio-1.8.3/python/segyio/su/0000775000372000037200000000000013407674361015706 5ustar travistravissegyio-1.8.3/python/segyio/su/file.py0000664000372000037200000000560313407674361017203 0ustar travistravisfrom ..open import infer_geometry from ..segy import SegyFile from . import words import numpy class sufile(SegyFile): def __init__(self, *args, **kwargs): super(sufile, self).__init__(*args, **kwargs) @property def text(self): raise NotImplementedError @property def bin(self): raise NotImplementedError @bin.setter def bin(self, _): raise NotImplementedError def open(filename, mode = 'r', iline = 189, xline = 193, strict = True, ignore_geometry = False, endian = 'big' ): """Open a seismic unix file. Behaves identically to open(), except it expects the seismic unix format, not SEG-Y. Parameters ---------- filename : str Path to file to open mode : {'r', 'r+'} File access mode, read-only ('r', default) or read-write ('r+') iline : int or segyio.TraceField Inline number field in the trace headers. Defaults to 189 as per the SEG-Y rev1 specification xline : int or segyio.TraceField Crossline number field in the trace headers. Defaults to 193 as per the SEG-Y rev1 specification strict : bool, optional Abort if a geometry cannot be inferred. Defaults to True. ignore_geometry : bool, optional Opt out on building geometry information, useful for e.g. shot organised files. Defaults to False. endian : {'big', 'msb', 'little', 'lsb'} File endianness, big/msb (default) or little/lsb Returns ------- file : segyio.su.file An open seismic unix file handle Raises ------ ValueError If the mode string contains 'w', as it would truncate the file See also -------- segyio.open : SEG-Y open Notes ----- .. versionadded:: 1.8 """ if 'w' in mode: problem = 'w in mode would truncate the file' solution = 'use r+ to open in read-write' raise ValueError(', '.join((problem, solution))) endians = { 'little': 256, # (1 << 8) 'lsb': 256, 'big': 0, 'msb': 0, } if endian not in endians: problem = 'unknown endianness, must be one of: ' candidates = ' '.join(endians.keys()) raise ValueError(problem + candidates) from .. import _segyio fd = _segyio.segyiofd(str(filename), mode, endians[endian]) fd.suopen() metrics = fd.metrics() f = sufile( fd, filename = str(filename), mode = mode, iline = iline, xline = xline, ) h0 = f.header[0] dt = h0[words.dt] / 1000.0 t0 = h0[words.delrt] samples = metrics['samplecount'] f._samples = (numpy.arange(samples) * dt) + t0 if ignore_geometry: return f return infer_geometry(f, metrics, iline, xline, strict) segyio-1.8.3/python/segyio/su/words.py0000664000372000037200000001101413407674361017413 0ustar travistravis"""Seismic Unix aliases Seismic Unix style aliases for binary and trace header fields. Notes ----- .. versionadded: 1.1 Seismic Unix does not have names for all possible fields, as it came around during an early revision of SEG-Y, and names for these fields are created by segyio in their absence. If Seismic Unix starts providing names for these fields, they will be added to these alies, and in conflicts take presedence after some time. If there are no conflicts, segyio names are considered for deprecation on a case-by-case basis, but will most likely be supported along with the Seismic Unix name. """ from ..tracefield import TraceField as tf from ..binfield import BinField as bf # the wonky #: before every line is so that sphinx' autodoc picks it up, and includes the constants in the documentation #: tracl = tf.TRACE_SEQUENCE_LINE #: tracr = tf.TRACE_SEQUENCE_FILE #: fldr = tf.FieldRecord #: tracf = tf.TraceNumber #: ep = tf.EnergySourcePoint #: cdp = tf.CDP #: cdpt = tf.CDP_TRACE #: trid = tf.TraceIdentificationCode #: nvs = tf.NSummedTraces #: nhs = tf.NStackedTraces #: duse = tf.DataUse #: offset = tf.offset #: gelev = tf.ReceiverGroupElevation #: selev = tf.SourceSurfaceElevation #: sdepth = tf.SourceDepth #: gdel = tf.ReceiverDatumElevation #: sdel = tf.SourceDatumElevation #: swdep = tf.SourceWaterDepth #: gwdep = tf.GroupWaterDepth #: scalel = tf.ElevationScalar #: scalco = tf.SourceGroupScalar #: sx = tf.SourceX #: sy = tf.SourceY #: gx = tf.GroupX #: gy = tf.GroupY #: counit = tf.CoordinateUnits #: wevel = tf.WeatheringVelocity #: swevel = tf.SubWeatheringVelocity #: sut = tf.SourceUpholeTime #: gut = tf.GroupUpholeTime #: sstat = tf.SourceStaticCorrection #: gstat = tf.GroupStaticCorrection #: tstat = tf.TotalStaticApplied #: laga = tf.LagTimeA #: lagb = tf.LagTimeB #: delrt = tf.DelayRecordingTime #: muts = tf.MuteTimeStart #: mute = tf.MuteTimeEND #: ns = tf.TRACE_SAMPLE_COUNT #: dt = tf.TRACE_SAMPLE_INTERVAL #: gain = tf.GainType #: igc = tf.InstrumentGainConstant #: igi = tf.InstrumentInitialGain #: corr = tf.Correlated #: sfs = tf.SweepFrequencyStart #: sfe = tf.SweepFrequencyEnd #: slen = tf.SweepLength #: styp = tf.SweepType #: stat = tf.SweepTraceTaperLengthStart #: stae = tf.SweepTraceTaperLengthEnd #: tatyp = tf.TaperType #: afilf = tf.AliasFilterFrequency #: afils = tf.AliasFilterSlope #: nofilf = tf.NotchFilterFrequency #: nofils = tf.NotchFilterSlope #: lcf = tf.LowCutFrequency #: hcf = tf.HighCutFrequency #: lcs = tf.LowCutSlope #: hcs = tf.HighCutSlope #: year = tf.YearDataRecorded #: day = tf.DayOfYear #: hour = tf.HourOfDay #: minute = tf.MinuteOfHour #: sec = tf.SecondOfMinute #: timbas = tf.TimeBaseCode #: trwf = tf.TraceWeightingFactor #: grnors = tf.GeophoneGroupNumberRoll1 #: grnofr = tf.GeophoneGroupNumberFirstTraceOrigField #: grnlof = tf.GeophoneGroupNumberLastTraceOrigField #: gaps = tf.GapSize #: otrav = tf.OverTravel #: cdpx = tf.CDP_X #: cdpy = tf.CDP_Y #: iline = tf.INLINE_3D #: xline = tf.CROSSLINE_3D #: sp = tf.ShotPoint #: scalsp = tf.ShotPointScalar #: trunit = tf.TraceValueMeasurementUnit #: tdcm = tf.TransductionConstantMantissa #: tdcp = tf.TransductionConstantPower #: tdunit = tf.TransductionUnit #: triden = tf.TraceIdentifier #: sctrh = tf.ScalarTraceHeader #: stype = tf.SourceType #: sedm = tf.SourceEnergyDirectionMantissa #: sede = tf.SourceEnergyDirectionExponent #: smm = tf.SourceMeasurementMantissa #: sme = tf.SourceMeasurementExponent #: smunit = tf.SourceMeasurementUnit #: uint1 = tf.UnassignedInt1 #: uint2 = tf.UnassignedInt2 # binary #: jobid = bf.JobID #: lino = bf.LineNumber #: reno = bf.ReelNumber #: ntrpr = bf.Traces #: nart = bf.AuxTraces #: hdt = bf.Interval #: dto = bf.IntervalOriginal #: hns = bf.Samples #: nso = bf.SamplesOriginal #: format = bf.Format #: fold = bf.EnsembleFold #: tsort = bf.SortingCode #: vscode = bf.VerticalSum #: hsfs = bf.SweepFrequencyStart #: hsfe = bf.SweepFrequencyEnd #: hslen = bf.SweepLength #: hstyp = bf.Sweep #: schn = bf.SweepChannel #: hstas = bf.SweepTaperStart #: hstae = bf.SweepTaperEnd #: htatyp = bf.Taper #: hcorr = bf.CorrelatedTraces #: bgrcv = bf.BinaryGainRecovery #: rcvm = bf.AmplitudeRecovery #: mfeet = bf.MeasurementSystem #: polyt = bf.ImpulseSignalPolarity #: vpol = bf.VibratoryPolarity #: unas1 = bf.Unassigned1 #: rev = bf.SEGYRevision #: trflag = bf.TraceFlag #: exth = bf.ExtendedHeaders #: unas2 = bf.Unassigned2 segyio-1.8.3/python/segyio/su/__init__.py0000664000372000037200000000005413407674361020016 0ustar travistravisfrom .words import * from .file import open segyio-1.8.3/python/segyio/segysampleformat.py0000664000372000037200000000041113407674361021207 0ustar travistravisfrom . import Enum class SegySampleFormat(Enum): IBM_FLOAT_4_BYTE = 1 SIGNED_INTEGER_4_BYTE = 2 SIGNED_SHORT_2_BYTE = 3 FIXED_POINT_WITH_GAIN_4_BYTE = 4 IEEE_FLOAT_4_BYTE = 5 NOT_IN_USE_1 = 6 NOT_IN_USE_2 = 7 SIGNED_CHAR_1_BYTE = 8 segyio-1.8.3/python/segyio/field.py0000664000372000037200000004460413407674361016724 0ustar travistravisimport collections import segyio from .binfield import BinField from .tracefield import TraceField class Field(collections.MutableMapping): """ The Field implements the dict interface, with a fixed set of keys. It's used for both binary- and trace headers. Any modifications to this dict_like object will be reflected on disk. The keys can be integers, int_likes, or enumerations such as BinField, TraceField, and su. If raw, numerical offsets are used they must align with the defined byte offsets by the SEGY specification. Notes ----- .. versionadded:: 1.1 .. versionchanged:: 1.3 common dict operations (update, keys, values) .. versionchanged:: 1.6 more common dict operations (collections.MutableMapping) """ _bin_keys = [x for x in BinField.enums() if x != BinField.Unassigned1 and x != BinField.Unassigned2] _tr_keys = [x for x in TraceField.enums() if x != TraceField.UnassignedInt1 and x != TraceField.UnassignedInt2] _kwargs = { 'tracl' : TraceField.TRACE_SEQUENCE_LINE, 'tracr' : TraceField.TRACE_SEQUENCE_FILE, 'fldr' : TraceField.FieldRecord, 'tracf' : TraceField.TraceNumber, 'ep' : TraceField.EnergySourcePoint, 'cdp' : TraceField.CDP, 'cdpt' : TraceField.CDP_TRACE, 'trid' : TraceField.TraceIdentificationCode, 'nvs' : TraceField.NSummedTraces, 'nhs' : TraceField.NStackedTraces, 'duse' : TraceField.DataUse, 'offset': TraceField.offset, 'gelev' : TraceField.ReceiverGroupElevation, 'selev' : TraceField.SourceSurfaceElevation, 'sdepth': TraceField.SourceDepth, 'gdel' : TraceField.ReceiverDatumElevation, 'sdel' : TraceField.SourceDatumElevation, 'swdep' : TraceField.SourceWaterDepth, 'gwdep' : TraceField.GroupWaterDepth, 'scalel': TraceField.ElevationScalar, 'scalco': TraceField.SourceGroupScalar, 'sx' : TraceField.SourceX, 'sy' : TraceField.SourceY, 'gx' : TraceField.GroupX, 'gy' : TraceField.GroupY, 'counit': TraceField.CoordinateUnits, 'wevel' : TraceField.WeatheringVelocity, 'swevel': TraceField.SubWeatheringVelocity, 'sut' : TraceField.SourceUpholeTime, 'gut' : TraceField.GroupUpholeTime, 'sstat' : TraceField.SourceStaticCorrection, 'gstat' : TraceField.GroupStaticCorrection, 'tstat' : TraceField.TotalStaticApplied, 'laga' : TraceField.LagTimeA, 'lagb' : TraceField.LagTimeB, 'delrt' : TraceField.DelayRecordingTime, 'muts' : TraceField.MuteTimeStart, 'mute' : TraceField.MuteTimeEND, 'ns' : TraceField.TRACE_SAMPLE_COUNT, 'dt' : TraceField.TRACE_SAMPLE_INTERVAL, 'gain' : TraceField.GainType, 'igc' : TraceField.InstrumentGainConstant, 'igi' : TraceField.InstrumentInitialGain, 'corr' : TraceField.Correlated, 'sfs' : TraceField.SweepFrequencyStart, 'sfe' : TraceField.SweepFrequencyEnd, 'slen' : TraceField.SweepLength, 'styp' : TraceField.SweepType, 'stat' : TraceField.SweepTraceTaperLengthStart, 'stae' : TraceField.SweepTraceTaperLengthEnd, 'tatyp' : TraceField.TaperType, 'afilf' : TraceField.AliasFilterFrequency, 'afils' : TraceField.AliasFilterSlope, 'nofilf': TraceField.NotchFilterFrequency, 'nofils': TraceField.NotchFilterSlope, 'lcf' : TraceField.LowCutFrequency, 'hcf' : TraceField.HighCutFrequency, 'lcs' : TraceField.LowCutSlope, 'hcs' : TraceField.HighCutSlope, 'year' : TraceField.YearDataRecorded, 'day' : TraceField.DayOfYear, 'hour' : TraceField.HourOfDay, 'minute': TraceField.MinuteOfHour, 'sec' : TraceField.SecondOfMinute, 'timbas': TraceField.TimeBaseCode, 'trwf' : TraceField.TraceWeightingFactor, 'grnors': TraceField.GeophoneGroupNumberRoll1, 'grnofr': TraceField.GeophoneGroupNumberFirstTraceOrigField, 'grnlof': TraceField.GeophoneGroupNumberLastTraceOrigField, 'gaps' : TraceField.GapSize, 'otrav' : TraceField.OverTravel, 'cdpx' : TraceField.CDP_X, 'cdpy' : TraceField.CDP_Y, 'iline' : TraceField.INLINE_3D, 'xline' : TraceField.CROSSLINE_3D, 'sp' : TraceField.ShotPoint, 'scalsp': TraceField.ShotPointScalar, 'trunit': TraceField.TraceValueMeasurementUnit, 'tdcm' : TraceField.TransductionConstantMantissa, 'tdcp' : TraceField.TransductionConstantPower, 'tdunit': TraceField.TransductionUnit, 'triden': TraceField.TraceIdentifier, 'sctrh' : TraceField.ScalarTraceHeader, 'stype' : TraceField.SourceType, 'sedm' : TraceField.SourceEnergyDirectionMantissa, 'sede' : TraceField.SourceEnergyDirectionExponent, 'smm' : TraceField.SourceMeasurementMantissa, 'sme' : TraceField.SourceMeasurementExponent, 'smunit': TraceField.SourceMeasurementUnit, 'uint1' : TraceField.UnassignedInt1, 'uint2' : TraceField.UnassignedInt2, 'jobid' : BinField.JobID, 'lino' : BinField.LineNumber, 'reno' : BinField.ReelNumber, 'ntrpr' : BinField.Traces, 'nart' : BinField.AuxTraces, 'hdt' : BinField.Interval, 'dto' : BinField.IntervalOriginal, 'hns' : BinField.Samples, 'nso' : BinField.SamplesOriginal, 'format': BinField.Format, 'fold' : BinField.EnsembleFold, 'tsort' : BinField.SortingCode, 'vscode': BinField.VerticalSum, 'hsfs' : BinField.SweepFrequencyStart, 'hsfe' : BinField.SweepFrequencyEnd, 'hslen' : BinField.SweepLength, 'hstyp' : BinField.Sweep, 'schn' : BinField.SweepChannel, 'hstas' : BinField.SweepTaperStart, 'hstae' : BinField.SweepTaperEnd, 'htatyp': BinField.Taper, 'hcorr' : BinField.CorrelatedTraces, 'bgrcv' : BinField.BinaryGainRecovery, 'rcvm' : BinField.AmplitudeRecovery, 'mfeet' : BinField.MeasurementSystem, 'polyt' : BinField.ImpulseSignalPolarity, 'vpol' : BinField.VibratoryPolarity, 'unas1' : BinField.Unassigned1, 'rev' : BinField.SEGYRevision, 'trflag': BinField.TraceFlag, 'exth' : BinField.ExtendedHeaders, 'unas2' : BinField.Unassigned2, } def __init__(self, buf, kind, traceno = None, filehandle = None, readonly = True): # do setup of kind/keys first, so that keys() work. if this method # throws, we want repr() to be well-defined for backtrace, and that # requires _keys if kind == 'binary': self._keys = self._bin_keys self.kind = BinField elif kind == 'trace': self._keys = self._tr_keys self.kind = TraceField else: raise ValueError('Unknown header type {}'.format(kind)) self.buf = buf self.traceno = traceno self.filehandle = filehandle self.getfield = segyio._segyio.getfield self.putfield = segyio._segyio.putfield self.readonly = readonly def fetch(self, buf = None, traceno = None): """Fetch the header from disk This object will read header when it is constructed, which means it might be out-of-date if the file is updated through some other handle. This method is largely meant for internal use - if you need to reload disk contents, use ``reload``. Fetch does not update any internal state (unless `buf` is ``None`` on a trace header, and the read succeeds), but returns the fetched header contents. This method can be used to reposition the trace header, which is useful for constructing generators. If this is called on a writable, new file, and this header has not yet been written to, it will successfully return an empty buffer that, when written to, will be reflected on disk. Parameters ---------- buf : bytearray buffer to read into instead of ``self.buf`` traceno : int Returns ------- buf : bytearray Notes ----- .. versionadded:: 1.6 This method is not intended as user-oriented functionality, but might be useful in high-performance code. """ if buf is None: buf = self.buf if traceno is None: traceno = self.traceno try: if self.kind == TraceField: if traceno is None: return buf return self.filehandle.getth(traceno, buf) else: return self.filehandle.getbin() except IOError: if not self.readonly: # the file was probably newly created and the trace header # hasn't been written yet, and we set the buffer to zero. if # this is the case we want to try and write it later, and if # the file was broken, permissions were wrong etc writing will # fail too # # if the file is opened read-only and this happens, there's no # way to actually write and the error is an actual error return bytearray(len(self.buf)) else: raise def reload(self): """ This object will read header when it is constructed, which means it might be out-of-date if the file is updated through some other handle. It's rarely required to call this method, and it's a symptom of fragile code. However, if you have multiple handles to the same header, it might be necessary. Consider the following example:: >>> x = f.header[10] >>> y = f.header[10] >>> x[1, 5] { 1: 5, 5: 10 } >>> y[1, 5] { 1: 5, 5: 10 } >>> x[1] = 6 >>> x[1], y[1] # write to x[1] is invisible to y 6, 5 >>> y.reload() >>> x[1], y[1] 6, 6 >>> x[1] = 5 >>> x[1], y[1] 5, 6 >>> y[5] = 1 >>> x.reload() >>> x[1], y[1, 5] # the write to x[1] is lost 6, { 1: 6; 5: 1 } In segyio, headers writes are atomic, and the write to disk writes the full cache. If this cache is out of date, some writes might get lost, even though the updates are compatible. The fix to this issue is either to use ``reload`` and maintain buffer consistency, or simply don't let header handles alias and overlap in lifetime. Notes ----- .. versionadded:: 1.6 """ self.buf = self.fetch(buf = self.buf) return self def flush(self): """Commit backing storage to disk This method is largely internal, and it is not necessary to call this from user code. It should not be explicitly invoked and may be removed in future versions. """ if self.kind == TraceField: self.filehandle.putth(self.traceno, self.buf) elif self.kind == BinField: self.filehandle.putbin(self.buf) else: msg = 'Object corrupted: kind {} not valid' raise RuntimeError(msg.format(self.kind)) def __getitem__(self, key): """d[key] Read the associated value of `key`. `key` can be any iterable, to retrieve multiple keys at once. In this case, a mapping of key -> value is returned. Parameters ---------- key : int, or iterable of int Returns ------- value : int or dict_like Notes ----- .. versionadded:: 1.1 .. note:: Since version 1.6, KeyError is appropriately raised on key misses, whereas ``IndexError`` was raised before. This is an old bug, since header types were documented to be dict-like. If you rely on catching key-miss errors in your code, you might want to handle both ``IndexError`` and ``KeyError`` for multi-version robustness. .. warning:: segyio considers reads/writes full headers, not individual fields, and does the read from disk when this class is constructed. If the file is updated through some other handle, including a secondary access via `f.header`, this cache might be out-of-date. Examples -------- Read a single value: >>> d[3213] 15000 Read multiple values at once: >>> d[37, 189] { 37: 5, 189: 2484 } >>> d[37, TraceField.INLINE_3D] { 37: 5, 189: 2484 } """ try: return self.getfield(self.buf, int(key)) except TypeError: pass return {self.kind(k): self.getfield(self.buf, int(k)) for k in key} def __setitem__(self, key, val): """d[key] = val Set d[key] to val. Setting keys commits changes to disk, although the changes may not be visible until the kernel schedules the write. Unlike d[key], this method does not support assigning multiple values at once. To set multiple values at once, use the `update` method. Parameters ---------- key : int_like val : int_like Returns ------- val : int The value set Notes ----- .. versionadded:: 1.1 .. note:: Since version 1.6, KeyError is appropriately raised on key misses, whereas ``IndexError`` was raised before. This is an old bug, since header types were documented to be dict-like. If you rely on catching key-miss errors in your code, you might want to handle both ``IndexError`` and ``KeyError`` for multi-version robustness. .. warning:: segyio considers reads/writes full headers, not individual fields, and does the read from disk when this class is constructed. If the file is updated through some other handle, including a secondary access via `f.header`, this cache might be out-of-date. That means writing an individual field will write the full header to disk, possibly overwriting previously set values. Examples -------- Set a value and keep in a variable: >>> x = header[189] = 5 >>> x 5 """ self.putfield(self.buf, key, val) self.flush() return val def __delitem__(self, key): """del d[key] 'Delete' the key by setting value to zero. Equivalent to ``d[key] = 0``. Notes ----- .. versionadded:: 1.6 """ self[key] = 0 def keys(self): """D.keys() -> a set-like object providing a view on D's keys""" return list(self._keys) def __len__(self): """x.__len__() <==> len(x)""" return len(self._keys) def __iter__(self): """x.__iter__() <==> iter(x)""" return iter(self._keys) def __eq__(self, other): """x.__eq__(y) <==> x == y""" if not isinstance(other, collections.Mapping): return NotImplemented if len(self) != len(other): return False def intkeys(d): return { int(k): v for k, v in d.items() } return intkeys(self) == intkeys(other) def update(self, *args, **kwargs): """d.update([E, ]**F) -> None. Update D from mapping/iterable E and F. Overwrite the values in `d` with the keys from `E` and `F`. If any key in `value` is invalid in `d`, ``KeyError`` is raised. This method is atomic - either all values in `value` are set in `d`, or none are. ``update`` does not commit a partially-updated version to disk. For kwargs, Seismic Unix-style names are supported. `BinField` and `TraceField` are not, because there are name collisions between them, although this restriction may be lifted in the future. Notes ----- .. versionchanged:: 1.3 Support for common dict operations (update, keys, values) .. versionchanged:: 1.6 Atomicity guarantee .. versionchanged:: 1.6 `**kwargs` support Examples -------- >>> e = { 1: 10, 9: 5 } >>> d.update(e) >>> l = [ (105, 11), (169, 4) ] >>> d.update(l) >>> d.update(e, iline=189, xline=193, hour=5) >>> d.update(sx=7) """ if len(args) > 1: msg = 'update expected at most 1 non-keyword argument, got {}' raise TypeError(msg.format(len(args))) buf = bytearray(self.buf) # Implementation largely borrowed from collections.mapping # If E present and has a .keys() method: for k in E: D[k] = E[k] # If E present and lacks .keys() method: for (k, v) in E: D[k] = v # In either case, this is followed by: for k, v in F.items(): D[k] = v if len(args) == 1: other = args[0] if isinstance(other, collections.Mapping): for key in other: self.putfield(buf, int(key), other[key]) elif hasattr(other, "keys"): for key in other.keys(): self.putfield(buf, int(key), other[key]) else: for key, value in other: self.putfield(buf, int(key), value) for key, value in kwargs.items(): self.putfield(buf, int(self._kwargs[key]), value) self.buf = buf self.flush() @classmethod def binary(cls, segy): buf = bytearray(segyio._segyio.binsize()) return Field(buf, kind='binary', filehandle=segy.xfd, readonly=segy.readonly, ).reload() @classmethod def trace(cls, traceno, segy): buf = bytearray(segyio._segyio.thsize()) return Field(buf, kind='trace', traceno=traceno, filehandle=segy.xfd, readonly=segy.readonly, ).reload() def __repr__(self): return repr(self[self.keys()]) segyio-1.8.3/python/segyio/create.py0000664000372000037200000001672613407674361017110 0ustar travistravisimport datetime import numpy import segyio from . import TraceSortingFormat def default_text_header(iline, xline, offset): lines = { 1: "DATE %s" % datetime.date.today().isoformat(), 2: "AN INCREASE IN AMPLITUDE EQUALS AN INCREASE IN ACOUSTIC IMPEDANCE", 3: "Written by libsegyio (python)", 11: "TRACE HEADER POSITION:", 12: " INLINE BYTES %03d-%03d | OFFSET BYTES %03d-%03d" % (iline, iline + 4, int(offset), int(offset) + 4), 13: " CROSSLINE BYTES %03d-%03d |" % (xline, xline + 4), 15: "END EBCDIC HEADER", } rows = segyio.create_text_header(lines) rows = bytearray(rows, 'ascii') # mutable array of bytes rows[-1] = 128 # \x80 -- Unsure if this is really required... return bytes(rows) # immutable array of bytes that is compatible with strings def structured(spec): if not hasattr(spec, 'ilines' ): return False if not hasattr(spec, 'xlines' ): return False if not hasattr(spec, 'offsets'): return False if spec.ilines is None: return False if spec.xlines is None: return False if spec.offsets is None: return False if not list(spec.ilines): return False if not list(spec.xlines): return False if not list(spec.offsets): return False return True def create(filename, spec): """Create a new segy file. Create a new segy file with the geometry and properties given by `spec`. This enables creating SEGY files from your data. The created file supports all segyio modes, but has an emphasis on writing. The spec must be complete, otherwise an exception will be raised. A default, empty spec can be created with ``segyio.spec()``. Very little data is written to the file, so just calling create is not sufficient to re-read the file with segyio. Rather, every trace header and trace must be written to the file to be considered complete. Create should be used together with python's ``with`` statement. This ensure the data is written. Please refer to the examples. The ``segyio.spec()`` function will default sorting, offsets and everything in the mandatory group, except format and samples, and requires the caller to fill in *all* the fields in either of the exclusive groups. If any field is missing from the first exclusive group, and the tracecount is set, the resulting file will be considered unstructured. If the tracecount is set, and all fields of the first exclusive group are specified, the file is considered structured and the tracecount is inferred from the xlines/ilines/offsets. The offsets are defaulted to ``[1]`` by ``segyio.spec()``. Parameters ---------- filename : str Path to file to create spec : segyio.spec Structure of the segy file Returns ------- file : segyio.SegyFile An open segyio file handle, similar to that returned by `segyio.open` See also -------- segyio.spec : template for the `spec` argument Notes ----- .. versionadded:: 1.1 .. versionchanged:: 1.4 Support for creating unstructured files .. versionchanged:: 1.8 Support for creating lsb files The ``spec`` is any object that has the following attributes Mandatory:: iline : int or segyio.BinField xline : int or segyio.BinField samples : array of int format : { 1, 5 } 1 = IBM float, 5 = IEEE float Exclusive:: ilines : array_like of int xlines : array_like of int offsets : array_like of int sorting : int or segyio.TraceSortingFormat OR tracecount : int Optional:: ext_headers : int endian : str { 'big', 'msb', 'little', 'lsb' } defaults to 'big' Examples -------- Create a file: >>> spec = segyio.spec() >>> spec.ilines = [1, 2, 3, 4] >>> spec.xlines = [11, 12, 13] >>> spec.samples = list(range(50)) >>> spec.sorting = 2 >>> spec.format = 1 >>> with segyio.create(path, spec) as f: ... ## fill the file with data ... pass ... Copy a file, but shorten all traces by 50 samples: >>> with segyio.open(srcpath) as src: ... spec = segyio.spec() ... spec.sorting = src.sorting ... spec.format = src.format ... spec.samples = src.samples[:len(src.samples) - 50] ... spec.ilines = src.ilines ... spec.xline = src.xlines ... with segyio.create(dstpath, spec) as dst: ... dst.text[0] = src.text[0] ... dst.bin = src.bin ... dst.header = src.header ... dst.trace = src.trace Copy a file, but shift samples time by 50: >>> with segyio.open(srcpath) as src: ... delrt = 50 ... spec = segyio.spec() ... spec.samples = src.samples + delrt ... spec.ilines = src.ilines ... spec.xline = src.xlines ... with segyio.create(dstpath, spec) as dst: ... dst.text[0] = src.text[0] ... dst.bin = src.bin ... dst.header = src.header ... dst.header = { TraceField.DelayRecordingTime: delrt } ... dst.trace = src.trace Copy a file, but shorten all traces by 50 samples (since v1.4): >>> with segyio.open(srcpath) as src: ... spec = segyio.tools.metadata(src) ... spec.samples = spec.samples[:len(spec.samples) - 50] ... with segyio.create(dstpath, spec) as dst: ... dst.text[0] = src.text[0] ... dst.bin = src.bin ... dst.header = src.header ... dst.trace = src.trace """ from . import _segyio if not structured(spec): tracecount = spec.tracecount else: tracecount = len(spec.ilines) * len(spec.xlines) * len(spec.offsets) ext_headers = spec.ext_headers if hasattr(spec, 'ext_headers') else 0 samples = numpy.asarray(spec.samples) endians = { 'lsb': 256, # (1 << 8) 'little': 256, 'msb': 0, 'big': 0, } endian = spec.endian if hasattr(spec, 'endian') else 'big' if endian is None: endian = 'big' if endian not in endians: problem = 'unknown endianness {}, expected one of: ' opts = ' '.join(endians.keys()) raise ValueError(problem.format(endian) + opts) fd = _segyio.segyiofd(str(filename), 'w+', endians[endian]) fd.segymake( samples = len(samples), tracecount = tracecount, format = int(spec.format), ext_headers = int(ext_headers), ) f = segyio.SegyFile(fd, filename = str(filename), mode = 'w+', iline = int(spec.iline), xline = int(spec.xline), endian = endian, ) f._samples = samples if structured(spec): sorting = spec.sorting if hasattr(spec, 'sorting') else None if sorting is None: sorting = TraceSortingFormat.INLINE_SORTING f.interpret(spec.ilines, spec.xlines, spec.offsets, sorting) f.text[0] = default_text_header(f._il, f._xl, segyio.TraceField.offset) if len(samples) == 1: interval = int(samples[0] * 1000) else: interval = int((samples[1] - samples[0]) * 1000) f.bin.update( ntrpr = tracecount, nart = tracecount, hdt = interval, dto = interval, hns = len(samples), nso = len(samples), format = int(spec.format), exth = ext_headers, ) return f segyio-1.8.3/python/segyio/gather.py0000664000372000037200000001152313407674361017105 0ustar travistravisimport itertools import numpy as np import segyio.tools as tools class Gather(object): """ A gather is in this context the intersection of lines in a cube, i.e. all the offsets at some inline/crossline intersection. The primary data type is numpy.ndarray, with dimensions depending on the range of offsets specified. Implements a dict_like lookup with the line and offset numbers (labels), not 0-based indices. Notes ----- .. versionadded:: 1.1 """ def __init__(self, trace, iline, xline, offsets): # cache constructed modes for performance self.trace = trace self.iline = iline self.xline = xline self.offsets = offsets def __getitem__(self, index): """gather[i, x, o], gather[:,:,:] Get the gather or range of gathers, defined as offsets intersection between an in- and a crossline. Also works on post-stack files (with only 1 offset), although it is less useful in those cases. If offsets are omitted, the default is all offsets. A group of offsets is always returned as an offset-by-samples numpy.ndarray. If either inline, crossline, or both, are slices, a generator of such ndarrays are returned. If the slice of offsets misses all offsets, a special, empty ndarray is returned. Parameters ---------- i : int or slice inline x : int or slice crossline o : int or slice offsets (default is :) Returns ------- gather : numpy.ndarray or generator of numpy.ndarray Notes ----- .. versionadded:: 1.1 Examples -------- Read one offset at an intersection: >>> gather[200, 241, 25] # returns same shape as trace Read all offsets at an intersection: >>> gather[200, 241, :] # returns offsets x samples ndarray >>> # If no offset is specified, this is implicitly (:) >>> gather[200, 241, :] == gather[200, 241] All offsets for a set of ilines, intersecting one crossline: >>> gather[200:300, 241, :] == gather[200:300, 241] Some offsets for a set of ilines, interescting one crossline: >>> gather[200:300, 241, 10:25:5] Some offsets for a set of ilines and xlines. This effectively yields a subcube: >>> f.gather[200:300, 241:248, 1:10] """ if len(index) < 3: index = (index[0], index[1], None) il, xl, off = index if off is None and len(self.offsets) == 1: off = self.offsets[0] # if offset isn't specified, default to all, [:] off = off or slice(None) def isslice(x): return isinstance(x, slice) # gather[int,int,int] if not any(map(isslice, [il, xl, off])): o = self.iline.offsets[off] i = o + self.iline.heads[il] + self.xline.heads[xl] return self.trace[i] offs = off if isslice(off) else slice(off, off+1, 1) xs = list(filter(self.offsets.__contains__, range(*offs.indices(self.offsets[-1]+1)))) empty = np.empty(0, dtype = self.trace.dtype) # gather[int,int,:] if not any(map(isslice, [il, xl])): if len(xs) == 0: return empty i = self.iline.heads[il] + self.xline.heads[xl] return tools.collect(self.trace[i + self.iline.offsets[x]] for x in xs) # gather[:,:,:], gather[int,:,:], gather[:,int,:] # gather[:,:,int] etc def gen(): # precomputed xline number -> xline offset into the iline xlinds = { xlno: i for i, xlno in enumerate(self.xline.keys()) } # ranges over gathers are done on a by-line basis so lines can be # buffered, and traces can be read from the iline. This is the # least efficient when there are very few traces read per inline, # but huge savings with larger subcubes last_il = self.iline.keys()[-1] + 1 last_xl = self.xline.keys()[-1] + 1 il_slice = il if isslice(il) else slice(il, il+1) xl_slice = xl if isslice(xl) else slice(xl, xl+1) il_range = range(*il_slice.indices(last_il)) xl_range = range(*xl_slice.indices(last_xl)) if not isslice(off): for iline in self.iline[il_slice, off]: for xlno in xl_range: yield iline[xlinds[xlno]] return if len(xs) == 0: for _, _ in itertools.product(il_range, xl_range): yield empty return for ilno in il_range: iline = tools.collect(self.iline[ilno, off]) for x in xl_range: yield iline[:, xlinds[x]] return gen() segyio-1.8.3/python/segyio/depth.py0000664000372000037200000001163213407674361016740 0ustar travistravisimport numpy as np try: from future_builtins import zip except ImportError: pass from .tracesortingformat import TraceSortingFormat as Sorting from .trace import Sequence from .utils import castarray class Depth(Sequence): """ The Depth implements the array interface, where every array element, the depth, is a numpy.ndarray of a horizontal cut of the volume. As all arrays it can be random accessed, iterated over, and read strided. Please note that SEG-Y data is laid out trace-by-trace on disk, so accessing horizontal cuts (fixed z-coordinates in a cartesian grid) is *very* inefficient. This mode works even on unstructured files, because it is not reliant on in/crosslines to be sensible. Please note that in the case of unstructured depth slicing, the array shape == tracecount. Notes ----- .. versionadded:: 1.1 .. versionchanged:: 1.6 common list operations (collections.Sequence) .. versionchanged:: 1.7.1 enabled for unstructured files .. warning:: Accessing the file by depth (fixed z-coordinate) is inefficient because of poor locality and many reads. If you read more than a handful depths, consider using a faster mode. """ def __init__(self, fd): super(Depth, self).__init__(len(fd.samples)) self.filehandle = fd.xfd self.dtype = fd.dtype if fd.unstructured: self.shape = fd.tracecount self.offsets = 1 else: self.shape = (len(fd.fast), len(fd.slow)) self.offsets = len(fd.offsets) def __getitem__(self, i): """depth[i] ith depth, a horizontal cross-section of the file, starting at 0. depth[i] returns a numpy.ndarray, and changes to this array will *not* be reflected on disk. When i is a slice, a generator of numpy.ndarray is returned. The depth slices are returned as a fast-by-slow shaped array, i.e. an inline sorted file with 10 inlines and 5 crosslines has the shape (10,5). If the file is unsorted, the array shape == tracecount. Parameters ---------- i : int or slice Returns ------- depth : numpy.ndarray of dtype or generator of numpy.ndarray of dtype Notes ----- .. versionadded:: 1.1 .. warning:: The segyio 1.5 and 1.6 series, and 1.7.0, would return the depth_slice in the wrong shape for most files. Since segyio 1.7.1, the arrays have the correct shape, i.e. fast-by-slow. The underlying data was always fast-by-slow, so a numpy array reshape can fix programs using the 1.5 and 1.6 series. Behaves like [] for lists. Examples -------- Read a single cut (one sample per trace): >>> x = f.depth_slice[199] Copy every depth slice into a list: >>> l = [numpy.copy(x) for x in depth[:] Every third depth: >>> for d in depth[::3]: ... (d * 6).mean() Read up to 250: >>> for d in depth[:250]: ... d.mean() >>> len(ilines), len(xlines) (1, 6) >>> f.depth_slice[0] array([[0. , 0.01, 0.02, 0.03, 0.04, 0.05]], dtype=float32) """ try: i = self.wrapindex(i) buf = np.empty(self.shape, dtype=self.dtype) return self.filehandle.getdepth(i, buf.size, self.offsets, buf) except TypeError: def gen(): x = np.empty(self.shape, dtype=self.dtype) y = np.copy(x) for j in range(*i.indices(len(self))): self.filehandle.getdepth(j, x.size, self.offsets, x) x, y = y, x yield y return gen() def __setitem__(self, depth, val): """depth[i] = val Write the ith depth, a horizontal cross-section, of the file, starting at 0. It accepts any array_like, but `val` must be at least as big as the underlying data slice. If `val` is longer than the underlying trace, `val` is essentially truncated. Parameters ---------- i : int or slice val : array_like Notes ----- .. versionadded:: 1.1 Behaves like [] for lists. Examples -------- Copy a depth: >>> depth[4] = other[19] Copy consecutive depths, and assign to a sub volume (inject a sub cube into the larger volume): >>> depth[10:50] = other[:] Copy into every other depth from an iterable: >>> depth[::2] = other """ if isinstance(depth, slice): for i, x in zip(range(*depth.indices(len(self))), val): self[i] = x return val = castarray(val, dtype = self.dtype) self.filehandle.putdepth(depth, val.size, self.offsets, val) segyio-1.8.3/python/segyio/utils.py0000664000372000037200000000204713407674361016774 0ustar travistravisimport warnings import numpy as np def castarray(x, dtype): try: x.dtype except AttributeError: msg = 'Implicit conversion from {} to {} (performance)' warnings.warn(msg.format(type(x), np.ndarray), RuntimeWarning) try: x = np.require(x, dtype = dtype, requirements = 'CAW') except TypeError: x = np.fromiter(x, dtype = dtype) if not x.flags['C_CONTIGUOUS']: msg = 'Implicit conversion to contiguous array' warnings.warn(msg, RuntimeWarning) if x.dtype != dtype: # TODO: message depending on narrowing/float-conversion msg = 'Implicit conversion from {} to {} (narrowing)' warnings.warn(msg.format(x.dtype, dtype), RuntimeWarning) # Ensure the data is C-order contiguous, writable, and aligned, with # the appropriate dtype. it won't copy unless it has to, so it's # reasonably fast. return np.require(x, dtype = dtype, requirements = 'CAW') segyio-1.8.3/python/segyio/version.py0000664000372000037200000000002213407674361017310 0ustar travistravisversion = '1.8.3' segyio-1.8.3/python/segyio/segy.py0000664000372000037200000006311513407674361016606 0ustar travistravisimport warnings try: from future_builtins import zip range = xrange except (NameError, ImportError): pass import numpy as np from .gather import Gather from .line import Line from .trace import Trace, Header, Attributes, Text from .field import Field from .tracesortingformat import TraceSortingFormat class SegyFile(object): """ This class is not meant to be instantiated directly, but rather obtained from ``segyio.open`` or ``segyio.create``. """ _unstructured_errmsg = "File opened in unstructured mode." def __init__(self, fd, filename, mode, iline=189, xline=193, endian='big', ): self._filename = filename self._mode = mode self._il = iline self._xl = xline # property value holders self._ilines = None self._xlines = None self._offsets = None self._samples = None self._sorting = None # private values self._iline_length = None self._iline_stride = None self._xline_length = None self._xline_stride = None self.xfd = fd metrics = self.xfd.metrics() self._fmt = metrics['format'] self._tracecount = metrics['tracecount'] self._ext_headers = metrics['ext_headers'] try: self._dtype = np.dtype({ -1: np.float32, 1: np.float32, 2: np.int32, 3: np.int16, 5: np.float32, 8: np.int8, }[self._fmt]) except KeyError: problem = 'Unknown trace value format {}'.format(self._fmt) solution = 'falling back to ibm float' warnings.warn(', '.join((problem, solution))) self._fmt = 1 self._dtype = np.dtype(np.float32) self._trace = Trace(self.xfd, self.dtype, self.tracecount, metrics['samplecount'], self.readonly, ) self._header = Header(self) self._iline = None self._xline = None self._gather = None self.depth = None self.endian = endian super(SegyFile, self).__init__() def __str__(self): f = "SegyFile {}:".format(self._filename) if self.unstructured: il = " inlines: None" xl = " crosslines: None" of = " offsets: None" else: il = " inlines: {} [{}, {}]".format(len(self.ilines), self.ilines[0], self.ilines[-1]) xl = " crosslines: {} [{}, {}]".format(len(self.xlines), self.xlines[0], self.xlines[-1]) of = " offsets: {} [{}, {}]".format(len(self.offsets), self.offsets[0], self.offsets[-1]) tr = " traces: {}".format(self.tracecount) sm = " samples: {}".format(self.samples) fmt = " float representation: {}".format(self.format) props = [f, il, xl, tr, sm] if self.offsets is not None and len(self.offsets) > 1: props.append(of) props.append(fmt) return '\n'.join(props) def __repr__(self): return "SegyFile('{}', '{}', iline = {}, xline = {})".format( self._filename, self._mode, self._il, self._xl) def __enter__(self): return self def __exit__(self, type, value, traceback): self.close() def flush(self): """Flush the file Write the library buffers to disk, like C's ``fflush``. This method is mostly useful for testing. It is not necessary to call this method unless you want to observe your changes on-disk while the file is still open. The file will automatically be flushed for you if you use the `with` statement when your routine is completed. Notes ----- .. versionadded:: 1.1 .. warning:: This is not guaranteed to actually write changes to disk, it only flushes the library buffers. Your kernel is free to defer writing changes to disk until a later time. Examples -------- Flush: >>> with segyio.open(path) as f: ... # write something to f ... f.flush() """ self.xfd.flush() def close(self): """Close the file This method is mostly useful for testing. It is not necessary to call this method if you're using the `with` statement, which will close the file for you. Calling methods on a previously-closed file will raise `IOError`. Notes ----- .. versionadded:: 1.1 """ self.xfd.close() def mmap(self): """Memory map the file Memory map the file. This is an advanced feature for speed and optimization; however, it is no silver bullet. If your file is smaller than the memory available on your system this will likely result in faster reads and writes, especially for line modes. However, if the file is very large, or memory is very pressured, this optimization might cause overall system slowdowns. However, if you're opening the same file from many different instances of segyio then memory mapping may significantly reduce the memory pressure. If this call returns true, the file is memory mapped. If memory mapping was build-time disabled or is not available for your platform this call always return false. If the memory mapping is unsuccessful you can keep using segyio - reading and writing falls back on non-memory mapped features. Returns ------- success : bool Returns True if the file was successfully memory mapped, False if not Notes ----- .. versionadded:: 1.1 Examples -------- Memory map: >>> mapped = f.mmap() >>> if mapped: print( "File is memory mapped!" ) File is memory mapped! >>> pass # keep using segyio as per usual >>> print( f.trace[10][7] ) 1.02548 """ return self.xfd.mmap() @property def dtype(self): """ The data type object of the traces. This is the format most accurate and efficient to exchange with the underlying file, and the data type you will find the data traces. Returns ------- dtype : numpy.dtype Notes ----- .. versionadded:: 1.6 """ return self._dtype @property def sorting(self): """ Inline or crossline sorting, or Falsey (None or 0) if unstructured. Returns ------- sorting : int """ return self._sorting @property def tracecount(self): """Number of traces in this file Equivalent to ``len(f.trace)`` Returns ------- count : int Number of traces in this file """ return self._tracecount @property def samples(self): """ Return the array of samples with appropriate intervals. Returns ------- samples : numpy.ndarray of int Notes ----- It holds that ``len(f.samples) == len(f.trace[0])`` """ return self._samples @property def offsets(self): """ Return the array of offset names. For post-stack data, this array has a length of 1 Returns ------- offsets : numpy.ndarray of int """ return self._offsets @property def ext_headers(self): """Extra text headers The number of extra text headers, given by the ``ExtendedHeaders`` field in the binary header. Returns ------- headers : int Number of extra text headers """ return self._ext_headers @property def unstructured(self): """ If the file is unstructured, sophisticated addressing modes that require the file to represent a proper cube won't work, and only raw data reading and writing is supported. Returns ------- unstructured : bool ``True`` if this file is unstructured, ``False`` if not """ return self.ilines is None @property def header(self): """ Interact with segy in header mode Returns ------- header : Header Notes ----- .. versionadded:: 1.1 """ return self._header @header.setter def header(self, val): """headers macro assignment A convenient way for operating on all headers of a file is to use the default full-file range. It will write headers 0, 1, ..., n, but uses the iteration specified by the right-hand side (i.e. can skip headers etc). If the right-hand-side headers are exhausted before all the destination file headers the writing will stop, i.e. not all all headers in the destination file will be written to. Examples -------- Copy headers from file g to file f: >>> f.header = g.header Set offset field: >>> f.header = { TraceField.offset: 5 } Copy every 12th header from the file g to f's 0, 1, 2...: >>> f.header = g.header[::12] >>> f.header[0] == g.header[0] True >>> f.header[1] == g.header[12] True >>> f.header[2] == g.header[2] False >>> f.header[2] == g.header[24] True """ self.header[:] = val def attributes(self, field): """File-wide attribute (header word) reading Lazily gather a single header word for every trace in the file. The array can be sliced, supports index lookup, and numpy-style list-of-indices. Parameters ---------- field : int or segyio.TraceField field Returns ------- attrs : Attributes A sliceable array_like of header words Notes ----- .. versionadded:: 1.1 """ return Attributes(field, self.xfd, self.tracecount) @property def trace(self): """ Interact with segy in trace mode. Returns ------- trace : Trace Notes ----- .. versionadded:: 1.1 """ return self._trace @trace.setter def trace(self, val): """traces macro assignment Convenient way for setting traces from 0, 1, ... n, based on the iterable set of traces on the right-hand-side. If the right-hand-side traces are exhausted before all the destination file traces the writing will stop, i.e. not all all traces in the destination file will be written. Notes ----- .. versionadded:: 1.1 Examples -------- Copy traces from file f to file g: >>> f.trace = g.trace Copy first half of the traces from g to f: >>> f.trace = g.trace[:len(g.trace)/2] Fill the file with one trace (filled with zeros): >>> tr = np.zeros(f.samples) >>> f.trace = itertools.repeat(tr) For advanced users: sometimes you want to load the entire segy file to memory and apply your own structural manipulations or operations on it. Some segy files are very large and may not fit, in which case this feature will break down. This is an optimisation feature; using it should generally be driven by measurements. Read the first 10 traces: >>> f.trace.raw[0:10] Read *all* traces to memory: >>> f.trace.raw[:] Read every other trace to memory: >>> f.trace.raw[::2] """ self.trace[:] = val @property def ilines(self): """Inline labels The inline labels in this file, if structured, else None Returns ------- inlines : array_like of int or None """ return self._ilines @property def iline(self): """ Interact with segy in inline mode Returns ------- iline : Line or None Raises ------ ValueError If the file is unstructured Notes ----- .. versionadded:: 1.1 """ if self.unstructured: raise ValueError(self._unstructured_errmsg) if self._iline is not None: return self._iline self._iline = Line(self, self.ilines, self._iline_length, self._iline_stride, self.offsets, 'inline', ) return self._iline @iline.setter def iline(self, value): """inlines macro assignment Convenient way for setting inlines, from left-to-right as the inline numbers are specified in the file.ilines property, from an iterable set on the right-hand-side. If the right-hand-side inlines are exhausted before all the destination file inlines the writing will stop, i.e. not all all inlines in the destination file will be written. Notes ----- .. versionadded:: 1.1 Examples -------- Copy inlines from file f to file g: >>> f.iline = g.iline """ self.iline[:] = value @property def xlines(self): """Crossline labels The crosslane labels in this file, if structured, else None Returns ------- crosslines : array_like of int or None """ return self._xlines @property def xline(self): """ Interact with segy in crossline mode Returns ------- xline : Line or None Raises ------ ValueError If the file is unstructured Notes ----- .. versionadded:: 1.1 """ if self.unstructured: raise ValueError(self._unstructured_errmsg) if self._xline is not None: return self._xline self._xline = Line(self, self.xlines, self._xline_length, self._xline_stride, self.offsets, 'crossline', ) return self._xline @xline.setter def xline(self, value): """crosslines macro assignment Convenient way for setting crosslines, from left-to-right as the inline numbers are specified in the file.ilines property, from an iterable set on the right-hand-side. If the right-hand-side inlines are exhausted before all the destination file inlines the writing will stop, i.e. not all all inlines in the destination file will be written. Notes ----- .. versionadded:: 1.1 Examples -------- Copy crosslines from file f to file g: >>> f.xline = g.xline """ self.xline[:] = value @property def fast(self): """Access the 'fast' dimension This mode yields iline or xline mode, depending on which one is laid out `faster`, i.e. the line with linear disk layout. Use this mode if the inline/crossline distinction isn't as interesting as traversing in a fast manner (typically when you want to apply a function to the whole file, line-by-line). Returns ------- fast : Line line addressing mode Notes ----- .. versionadded:: 1.1 """ if self.sorting == TraceSortingFormat.INLINE_SORTING: return self.iline elif self.sorting == TraceSortingFormat.CROSSLINE_SORTING: return self.xline else: raise RuntimeError("Unknown sorting.") @property def slow(self): """Access the 'slow' dimension This mode yields iline or xline mode, depending on which one is laid out `slower`, i.e. the line with strided disk layout. Use this mode if the inline/crossline distinction isn't as interesting as traversing in the slower direction. Returns ------- slow : Line line addressing mode Notes ----- .. versionadded:: 1.1 """ if self.sorting == TraceSortingFormat.INLINE_SORTING: return self.xline elif self.sorting == TraceSortingFormat.CROSSLINE_SORTING: return self.iline else: raise RuntimeError("Unknown sorting.") @property def depth_slice(self): """ Interact with segy in depth slice mode (fixed z-coordinate) Returns ------- depth : Depth Notes ----- .. versionadded:: 1.1 .. versionchanged:: 1.7.1 enabled for unstructured files """ if self.depth is not None: return self.depth from .depth import Depth self.depth = Depth(self) return self.depth @depth_slice.setter def depth_slice(self, value): """depth macro assignment Convenient way for setting depth slices, from left-to-right as the depth slices numbers are specified in the file.depth_slice property, from an iterable set on the right-hand-side. If the right-hand-side depth slices are exhausted before all the destination file depth slices the writing will stop, i.e. not all all depth slices in the destination file will be written. Examples -------- Copy depth slices from file f to file g: >>> f.depth_slice = g.depth_slice Copy first half of the depth slices from g to f: >>> f.depth_slice = g.depth_slice[:g.samples/2]] """ self.depth_slice[:] = value @property def gather(self): """ Interact with segy in gather mode Returns ------- gather : Gather """ if self.unstructured: raise ValueError(self._unstructured_errmsg) if self._gather is not None: return self._gather self._gather = Gather(self.trace, self.iline, self.xline, self.offsets) return self._gather @property def text(self): """Interact with segy in text mode This mode gives access to reading and writing functionality for textual headers. The primary data type is the python string. Reading textual headers is done with ``[]``, and writing is done via assignment. No additional structure is built around the textual header, so everything is treated as one long string without line breaks. Returns ------- text : Text See also -------- segyio.tools.wrap : line-wrap a text header Notes ----- .. versionadded:: 1.1 """ return Text(self.xfd, self._ext_headers + 1) @property def bin(self): """ Interact with segy in binary mode This mode gives access to reading and writing functionality for the binary header. Please note that using numeric binary offsets uses the offset numbers from the specification, i.e. the first field of the binary header starts at 3201, not 1. If you're using the enumerations this is handled for you. Returns ------- binary : Field Notes ----- .. versionadded:: 1.1 """ return Field.binary(self) @bin.setter def bin(self, value): """Update binary header Update a value or replace the binary header Parameters ---------- value : dict_like dict_like, keys of int or segyio.BinField or segyio.su """ self.bin.update(value) @property def format(self): d = { -2: "4-byte native big-endian float", -1: "4-byte native little-endian float", 1: "4-byte IBM float", 2: "4-byte signed integer", 3: "2-byte signed integer", 4: "4-byte fixed point with gain", 5: "4-byte IEEE float", 8: "1-byte signed char" } class fmt: def __int__(inner): return self._fmt def __str__(inner): if not self._fmt in d: return "Unknown format" return d[self._fmt] return fmt() @property def readonly(self): """File is read-only Returns ------- readonly : bool True if this file is read-only Notes ----- .. versionadded:: 1.6 """ return '+' not in self._mode def interpret(self, ilines, xlines, offsets=None, sorting=TraceSortingFormat.INLINE_SORTING): """ (Re-)interpret structure on top of a file (Re-)interpret the structure of the file given the new sorting, ilines, xlines and offset indices. Note that file itself is not changed in any way, it is only segyio's interpretation of the file that changes. It's a way of telling segyio that a file is laid out in a particular way, even though the header fields say otherwise. `interpret` expect that the ilines-, xlines- and offsets-indices are unique. It also expect the dimensions of ilines, xlines and offset to match the tracecount. Parameters ---------- f : SegyFile ilines : array_like ilines indices in new structure xlines : array_like xlines indices in new structure offsets : array_like offset indices in new structure sorting : int, string or TraceSortingFormat Sorting in new structure Notes ----- .. versionadded:: 1.8 Examples -------- (Re)interpret the structure of the file: >>> ilines = [10, 11, 12, 13] >>> xlines = [20, 21, 22, 23, 24] >>> with segyio.open(file, ignore_geometry=True) as f: ... f.interpret(ilines, xlines) """ valid_sortings = { 1 : TraceSortingFormat.CROSSLINE_SORTING, 2 : TraceSortingFormat.INLINE_SORTING, 'iline' : TraceSortingFormat.INLINE_SORTING, 'inline' : TraceSortingFormat.INLINE_SORTING, 'xl' : TraceSortingFormat.CROSSLINE_SORTING, 'crossline' : TraceSortingFormat.CROSSLINE_SORTING, TraceSortingFormat.INLINE_SORTING : TraceSortingFormat.INLINE_SORTING, TraceSortingFormat.CROSSLINE_SORTING : TraceSortingFormat.CROSSLINE_SORTING, } if sorting not in valid_sortings: error = "Invalid sorting" solution = "valid sorting options are: {}".format(valid_sortings.keys()) raise ValueError('{}, {}'.format(error, solution)) if offsets is None: offsets = np.arange(1) ilines = np.copy(np.asarray(ilines, dtype=np.intc)) xlines = np.copy(np.asarray(xlines, dtype=np.intc)) offsets = np.copy(np.asarray(offsets, dtype=np.intc)) if np.unique(ilines).size != ilines.size: error = "Inlines inconsistent" solution = "expect all inlines to be unique" raise ValueError("{}, {}".format(error, solution)) if np.unique(xlines).size != xlines.size: error = "Crosslines inconsistent" solution = "expect all crosslines to be unique" raise ValueError("{}, {}".format(error, solution)) if np.unique(offsets).size != offsets.size: error = "Offsets inconsistent" solution = "expect all offsets to be unique" raise ValueError("{}, {}".format(error, solution)) if ilines.size * xlines.size * offsets.size != self.tracecount: error = ("Invalid dimensions, ilines ({}) * xlines ({}) * offsets " "({}) should match the number of traces ({})").format(ilines.size, xlines.size, offsets.size, self.tracecount) raise ValueError(error) from . import _segyio line_metrics = _segyio.line_metrics(sorting, self.tracecount, ilines.size, xlines.size, offsets.size) self._iline_length = line_metrics['iline_length'] self._iline_stride = line_metrics['iline_stride'] self._xline_length = line_metrics['xline_length'] self._xline_stride = line_metrics['xline_stride'] self._sorting = sorting self._offsets = offsets self._ilines = ilines self._xlines = xlines return self class spec(object): def __init__(self): self.iline = 189 self.ilines = None self.xline = 193 self.xlines = None self.offsets = [1] self.samples = None self.ext_headers = 0 self.format = None self.sorting = None self.endian = 'big' segyio-1.8.3/python/segyio/__init__.py0000664000372000037200000000703113407674361017371 0ustar travistravis"""segyio Welcome to segyio. For help, examples and reference, type ``help(function)`` in your favourite python interpreter, or ``pydoc function`` in the unix console. The segyio library attempts to be easy to use efficently for prototyping and interaction with possibly large segy files. File reading and writing is streaming, with large file support out of the box and without hassle. For a quick start on reading files, type ``help(segyio.open)``. An open segy file is interacted with in modes. For a reference with examples, please type ``help(segyio.segy)``, look at the online documentation at segyio.readthedocs.io, or run ``help()`` on the object returned by ``segyio.open``.. For documentation on individual modes, please refer to the individual modes with ``help(f.[mode])``, where ``f`` is an open file handle. The available modes are: * text, for textual headers including extended headers * bin, for the binary header * header, for the trace headers * trace, for trace data * iline, for inline biased operations * xline, for crossline biased operations * depth_slice, for depth biased operations * gather, for gather/intersaction biased operations The primary data type is the numpy.ndarray. All examples use ``np`` for the numpy namespace. That means that any function that returns a trace, a set of samples or even full lines, returns a numpy.ndarray. This enables quick and easy mathematical operations on the data you care about. Segyio is designed to blend into regular python code, so python concepts that map to segy operations are written to behave similarly. That means that sequences of data support list lookup, slicing (``f.trace[0:10:2]``), ``for x in`` etc. Please refer to the individual modes' documentation for a more extensive set of examples. For all slicing operations that segyio provides the underlying buffer is reused, so if you want to keep the data between iterations it is necessary to manually copy the data, e.g. ``numpy.copy()``. Please refer to the examples. """ class Enum(object): def __init__(self, enum_value): super(Enum, self).__init__() self._value = int(enum_value) def __int__(self): return int(self._value) def __str__(self): for k, v in self.__class__.__dict__.items(): if isinstance(v, int) and self._value == v: return k return "Unknown Enum" def __repr__(self): return str(self) def __hash__(self): return hash(self._value) def __eq__(self, other): try: o = int(other) except ValueError: return super(Enum, self).__eq__(other) else: return self._value == o def __ne__(self, other): return not self == other @classmethod def enums(cls): result = [] for v in cls.__dict__.values(): if isinstance(v, int): result.append(cls(v)) return sorted(result, key=int) from .binfield import BinField from .segysampleformat import SegySampleFormat from .tracesortingformat import TraceSortingFormat from .tracefield import TraceField from . import su from .open import open from .create import create from .segy import SegyFile, spec from .tools import dt, sample_indexes, create_text_header, native from .tools import collect, cube try: from .version import version as __version__ except ImportError: __version__ = '0.0.0' __copyright__ = 'Copyright 2016, Statoil ASA' __license__ = 'GNU Lesser General Public License version 3' __status__ = 'Production' segyio-1.8.3/python/segyio/trace.py0000664000372000037200000006346113407674361016741 0ustar travistravisimport collections import contextlib import itertools import warnings import sys try: from future_builtins import zip except ImportError: pass import numpy as np from .line import HeaderLine from .field import Field from .utils import castarray class Sequence(collections.Sequence): # unify the common optimisations and boilerplate of Trace, RawTrace, and # Header, which all obey the same index-oriented interface, and all share # length and wrap-around properties. # # It provides a useful negative-wrap index method which deals # appropriately with IndexError and python2-3 differences. def __init__(self, length): self.length = length def __len__(self): """x.__len__() <==> len(x)""" return self.length def __iter__(self): """x.__iter__() <==> iter(x)""" # __iter__ has a reasonable default implementation from # collections.Sequence. It's essentially this loop: # for i in range(len(self)): yield self[i] # However, in segyio that means the double-buffering, buffer reuse does # not happen, which is *much* slower (the allocation of otherwised # reused numpy objects takes about half the execution time), so # explicitly implement it as [:] return self[:] def wrapindex(self, i): if i < 0: i += len(self) if not 0 <= i < len(self): # in python2, int-slice comparison does not raise a type error, # (but returns False), so force a type-error if this still isn't an # int-like. _ = i + 0 raise IndexError('trace index out of range') return i class Trace(Sequence): """ The Trace implements the array interface, where every array element, the data trace, is a numpy.ndarray. As all arrays, it can be random accessed, iterated over, and read strided. Data is read lazily from disk, so iteration does not consume much memory. If you want eager reading, use Trace.raw. This mode gives access to reading and writing functionality for traces. The primary data type is ``numpy.ndarray``. Traces can be accessed individually or with python slices, and writing is done via assignment. Notes ----- .. versionadded:: 1.1 .. versionchanged:: 1.6 common list operations (collections.Sequence) Examples -------- Read all traces in file f and store in a list: >>> l = [numpy.copy(tr) for tr in trace[:]] Do numpy operations on a trace: >>> tr = trace[10] >>> tr = tr * 2 >>> tr = tr - 100 >>> avg = numpy.average(tr) Double every trace value and write to disk. Since accessing a trace gives a numpy value, to write to the respective trace we need its index: >>> for i, tr in enumerate(trace): ... tr = tr * 2 ... trace[i] = tr """ def __init__(self, filehandle, dtype, tracecount, samples, readonly): super(Trace, self).__init__(tracecount) self.filehandle = filehandle self.dtype = dtype self.shape = samples self.readonly = readonly def __getitem__(self, i): """trace[i] ith trace of the file, starting at 0. trace[i] returns a numpy array, and changes to this array will *not* be reflected on disk. When i is a slice, a generator of numpy arrays is returned. Parameters ---------- i : int or slice Returns ------- trace : numpy.ndarray of dtype or generator of numpy.ndarray of dtype Notes ----- .. versionadded:: 1.1 Behaves like [] for lists. .. note:: This operator reads lazily from the file, meaning the file is read on ``next()``, and only one trace is fixed in memory. This means segyio can run through arbitrarily large files without consuming much memory, but it is potentially slow if the goal is to read the entire file into memory. If that is the case, consider using `trace.raw`, which reads eagerly. Examples -------- Read every other trace: >>> for tr in trace[::2]: ... print(tr) Read all traces, last-to-first: >>> for tr in trace[::-1]: ... tr.mean() Read a single value. The second [] is regular numpy array indexing, and supports all numpy operations, including negative indexing and slicing: >>> trace[0][0] 1490.2 >>> trace[0][1] 1490.8 >>> trace[0][-1] 1871.3 >>> trace[-1][100] 1562.0 """ try: i = self.wrapindex(i) buf = np.zeros(self.shape, dtype = self.dtype) return self.filehandle.gettr(buf, i, 1, 1) except TypeError: def gen(): # double-buffer the trace. when iterating over a range, we want # to make sure the visible change happens as late as possible, # and that in the case of exception the last valid trace was # untouched. this allows for some fancy control flow, and more # importantly helps debugging because you can fully inspect and # interact with the last good value. x = np.zeros(self.shape, dtype=self.dtype) y = np.zeros(self.shape, dtype=self.dtype) for j in range(*i.indices(len(self))): self.filehandle.gettr(x, j, 1, 1) x, y = y, x yield y return gen() def __setitem__(self, i, val): """trace[i] = val Write the ith trace of the file, starting at 0. It accepts any array_like, but val must be at least as big as the underlying data trace. If val is longer than the underlying trace, it is essentially truncated. For the best performance, val should be a numpy.ndarray of sufficient size and same dtype as the file. segyio will warn on mismatched types, and attempt a conversion for you. Data is written immediately to disk. If writing multiple traces at once, and a write fails partway through, the resulting file is left in an unspecified state. Parameters ---------- i : int or slice val : array_like Notes ----- .. versionadded:: 1.1 Behaves like [] for lists. Examples -------- Write a single trace: >>> trace[10] = list(range(1000)) Write multiple traces: >>> trace[10:15] = np.array([cube[i] for i in range(5)]) Write multiple traces with stride: >>> trace[10:20:2] = np.array([cube[i] for i in range(5)]) """ if isinstance(i, slice): for j, x in zip(range(*i.indices(len(self))), val): self[j] = x return xs = castarray(val, self.dtype) # TODO: check if len(xs) > shape, and optionally warn on truncating # writes self.filehandle.puttr(self.wrapindex(i), xs) def __repr__(self): return "Trace(traces = {}, samples = {})".format(len(self), self.shape) @property def raw(self): """ An eager version of Trace Returns ------- raw : RawTrace """ return RawTrace(self.filehandle, self.dtype, len(self), self.shape, self.readonly, ) @property @contextlib.contextmanager def ref(self): """ A write-back version of Trace Returns ------- ref : RefTrace `ref` is returned in a context manager, and must be in a ``with`` statement Notes ----- .. versionadded:: 1.6 Examples -------- >>> with trace.ref as ref: ... ref[10] += 1.617 """ x = RefTrace(self.filehandle, self.dtype, len(self), self.shape, self.readonly, ) yield x x.flush() class RawTrace(Trace): """ Behaves exactly like trace, except reads are done eagerly and returned as numpy.ndarray, instead of generators of numpy.ndarray. """ def __init__(self, *args): super(RawTrace, self).__init__(*args) def __getitem__(self, i): """trace[i] Eagerly read the ith trace of the file, starting at 0. trace[i] returns a numpy array, and changes to this array will *not* be reflected on disk. When i is a slice, this returns a 2-dimensional numpy.ndarray . Parameters ---------- i : int or slice Returns ------- trace : numpy.ndarray of dtype Notes ----- .. versionadded:: 1.1 Behaves like [] for lists. .. note:: Reading this way is more efficient if you know you can afford the extra memory usage. It reads the requested traces immediately to memory. """ try: i = self.wrapindex(i) buf = np.zeros(self.shape, dtype = self.dtype) return self.filehandle.gettr(buf, i, 1, 1) except TypeError: indices = i.indices(len(self)) start, _, step = indices length = len(range(*indices)) buf = np.empty((length, self.shape), dtype = self.dtype) return self.filehandle.gettr(buf, start, step, length) def fingerprint(x): return hash(bytes(x.data)) class RefTrace(Trace): """ Behaves like trace, except changes to the returned numpy arrays *are* reflected on disk. Operations have to be in-place on the numpy array, so assignment on a trace will not work. This feature exists to support code like:: >>> with ref as r: ... for x, y in zip(r, src): ... numpy.copyto(x, y + 10) This class is not meant to be instantiated directly, but returned by :attr:`Trace.ref`. This feature requires a context manager, to guarantee modifications are written back to disk. """ def __init__(self, *args): super(RefTrace, self).__init__(*args) self.refs = {} def flush(self): """ Commit cached writes to the file handle. Does not flush libc buffers or notifies the kernel, so these changes may not immediately be visible to other processes. Updates the fingerprints whena writes happen, so successive ``flush()`` invocations are no-ops. It is not necessary to call this method in user code. Notes ----- .. versionadded:: 1.6 This method is not intended as user-oriented functionality, but might be useful in certain contexts to provide stronger guarantees. """ garbage = [] for i, (x, signature) in self.refs.items(): if sys.getrefcount(x) == 3: garbage.append(i) if fingerprint(x) == signature: continue self.filehandle.puttr(i, x) signature = fingerprint(x) # to avoid too many resource leaks, when this dict is the only one # holding references to already-produced traces, clear them for i in garbage: del self.refs[i] def fetch(self, i, buf = None): if buf is None: buf = np.zeros(self.shape, dtype = self.dtype) try: self.filehandle.gettr(buf, i, 1, 1) except IOError: if not self.readonly: # if the file is opened read-only and this happens, there's no # way to actually write and the error is an actual error buf.fill(0) else: raise return buf def __getitem__(self, i): """trace[i] Read the ith trace of the file, starting at 0. trace[i] returns a numpy array, but unlike Trace, changes to this array *will* be reflected on disk. The modifications must happen to the actual array (views are ok), so in-place operations work, but assignments will not:: >>> with ref as ref: ... x = ref[10] ... x += 1.617 # in-place, works ... numpy.copyto(x, x + 10) # works ... x = x + 10 # re-assignment, won't change the original x Works on newly created files that has yet to have any traces written, which opens up a natural way of filling newly created files with data. When getting unwritten traces, a trace filled with zeros is returned. Parameters ---------- i : int or slice Returns ------- trace : numpy.ndarray of dtype Notes ----- .. versionadded:: 1.6 Behaves like [] for lists. Examples -------- Merge two files with a binary operation. Relies on python3 iterator zip: >>> with ref as ref: ... for x, lhs, rhs in zip(ref, L, R): ... numpy.copyto(x, lhs + rhs) Create a file and fill with data (the repeated trace index): >>> f = create() >>> with f.trace.ref as ref: ... for i, x in enumerate(ref): ... x.fill(i) """ try: i = self.wrapindex(i) # we know this class is only used in context managers, so we know # refs don't escape (with expectation of being written), so # preserve all refs yielded with getitem(int) # # using ref[int] is problematic and pointless, we need to handle # this scenario gracefully: # with f.trace.ref as ref: # x = ref[10] # x[5] = 0 # # invalidate other refs # y = ref[11] # y[6] = 1.6721 # # # if we don't preserve returned individual getitems, this # # write is lost # x[5] = 52 # # for slices, we know that references terminate with every # iteration anyway, multiple live references cannot happen if i in self.refs: return self.refs[i][0] x = self.fetch(i) self.refs[i] = (x, fingerprint(x)) return x except TypeError: def gen(): x = np.zeros(self.shape, dtype = self.dtype) try: for j in range(*i.indices(len(self))): x = self.fetch(j, x) y = fingerprint(x) yield x if not fingerprint(x) == y: self.filehandle.puttr(j, x) finally: # the last yielded item is available after the loop, so # preserve it and check if it's been updated on exit self.refs[j] = (x, y) return gen() class Header(Sequence): """Interact with segy in header mode This mode gives access to reading and writing functionality of headers, both in individual (trace) mode and line mode. The returned header implements a dict_like object with a fixed set of keys, given by the SEG-Y standard. The Header implements the array interface, where every array element, the data trace, is a numpy.ndarray. As all arrays, it can be random accessed, iterated over, and read strided. Data is read lazily from disk, so iteration does not consume much memory. Notes ----- .. versionadded:: 1.1 .. versionchanged:: 1.6 common list operations (collections.Sequence) """ def __init__(self, segy): self.segy = segy super(Header, self).__init__(segy.tracecount) def __getitem__(self, i): """header[i] ith header of the file, starting at 0. Parameters ---------- i : int or slice Returns ------- field : Field dict_like header Notes ----- .. versionadded:: 1.1 Behaves like [] for lists. Examples -------- Reading a header: >>> header[10] Read a field in the first 5 headers: >>> [x[25] for x in header[:5]] [1, 2, 3, 4] Read a field in every other header: >>> [x[37] for x in header[::2]] [1, 3, 1, 3, 1, 3] """ try: i = self.wrapindex(i) return Field.trace(traceno = i, segy = self.segy) except TypeError: def gen(): # double-buffer the header. when iterating over a range, we # want to make sure the visible change happens as late as # possible, and that in the case of exception the last valid # header was untouched. this allows for some fancy control # flow, and more importantly helps debugging because you can # fully inspect and interact with the last good value. x = Field.trace(None, self.segy) buf = bytearray(x.buf) for j in range(*i.indices(len(self))): # skip re-invoking __getitem__, just update the buffer # directly with fetch, and save some initialisation work buf = x.fetch(buf, j) x.buf[:] = buf x.traceno = j yield x return gen() def __setitem__(self, i, val): """header[i] = val Write the ith header of the file, starting at 0. Unlike data traces (which return numpy.ndarrays), changes to returned headers being iterated over *will* be reflected on disk. Parameters ---------- i : int or slice val : Field or array_like of dict_like Notes ----- .. versionadded:: 1.1 Behaves like [] for lists Examples -------- Copy a header to a different trace: >>> header[28] = header[29] Write multiple fields in a trace: >>> header[10] = { 37: 5, TraceField.INLINE_3D: 2484 } Set a fixed set of values in all headers: >>> for x in header[:]: ... x[37] = 1 ... x.update({ TraceField.offset: 1, 2484: 10 }) Write a field in multiple headers >>> for x in header[:10]: ... x.update({ TraceField.offset : 2 }) Write a field in every other header: >>> for x in header[::2]: ... x.update({ TraceField.offset : 2 }) """ x = self[i] try: x.update(val) except AttributeError: if isinstance(val, Field) or isinstance(val, dict): val = itertools.repeat(val) for h, v in zip(x, val): h.update(v) @property def iline(self): """ Headers, accessed by inline Returns ------- line : HeaderLine """ return HeaderLine(self, self.segy.iline, 'inline') @iline.setter def iline(self, value): """Write iterables to lines Examples: Supports writing to *all* crosslines via assignment, regardless of data source and format. Will respect the sample size and structure of the file being assigned to, so if the argument traces are longer than that of the file being written to the surplus data will be ignored. Uses same rules for writing as `f.iline[i] = x`. """ for i, src in zip(self.segy.ilines, value): self.iline[i] = src @property def xline(self): """ Headers, accessed by crossline Returns ------- line : HeaderLine """ return HeaderLine(self, self.segy.xline, 'crossline') @xline.setter def xline(self, value): """Write iterables to lines Examples: Supports writing to *all* crosslines via assignment, regardless of data source and format. Will respect the sample size and structure of the file being assigned to, so if the argument traces are longer than that of the file being written to the surplus data will be ignored. Uses same rules for writing as `f.xline[i] = x`. """ for i, src in zip(self.segy.xlines, value): self.xline[i] = src class Attributes(Sequence): """File-wide attribute (header word) reading Lazily read a single header word for every trace in the file. The Attributes implement the array interface, and will behave as expected when indexed and sliced. Notes ----- .. versionadded:: 1.1 """ def __init__(self, field, filehandle, tracecount): super(Attributes, self).__init__(tracecount) self.field = field self.filehandle = filehandle self.tracecount = tracecount self.dtype = np.intc def __iter__(self): # attributes requires a custom iter, because self[:] returns a numpy # array, which in itself is iterable, but not an iterator return iter(self[:]) def __getitem__(self, i): """attributes[:] Parameters ---------- i : int or slice or array_like Returns ------- attributes : array_like of dtype Examples -------- Read all unique sweep frequency end: >>> end = segyio.TraceField.SweepFrequencyEnd >>> sfe = np.unique(f.attributes( end )[:]) Discover the first traces of each unique sweep frequency end: >>> end = segyio.TraceField.SweepFrequencyEnd >>> attrs = f.attributes(end) >>> sfe, tracenos = np.unique(attrs[:], return_index = True) Scatter plot group x/y-coordinates with SFEs (using matplotlib): >>> end = segyio.TraceField.SweepFrequencyEnd >>> attrs = f.attributes(end) >>> _, tracenos = np.unique(attrs[:], return_index = True) >>> gx = f.attributes(segyio.TraceField.GroupX)[tracenos] >>> gy = f.attributes(segyio.TraceField.GroupY)[tracenos] >>> scatter(gx, gy) """ try: xs = np.asarray(i, dtype = self.dtype) xs = xs.astype(dtype = self.dtype, order = 'C', copy = False) attrs = np.empty(len(xs), dtype = self.dtype) return self.filehandle.field_foreach(attrs, xs, self.field) except TypeError: try: i = slice(i, i + 1, 1) except TypeError: pass traces = self.tracecount filehandle = self.filehandle field = self.field start, stop, step = i.indices(traces) indices = range(start, stop, step) attrs = np.empty(len(indices), dtype = self.dtype) return filehandle.field_forall(attrs, start, stop, step, field) class Text(Sequence): """Interact with segy in text mode This mode gives access to reading and writing functionality for textual headers. The primary data type is the python string. Reading textual headers is done with [], and writing is done via assignment. No additional structure is built around the textual header, so everything is treated as one long string without line breaks. Notes ----- .. versionchanged:: 1.7 common list operations (collections.Sequence) """ def __init__(self, filehandle, textcount): super(Text, self).__init__(textcount) self.filehandle = filehandle def __getitem__(self, i): """text[i] Read the text header at i. 0 is the mandatory, main Examples -------- Print the textual header: >>> print(f.text[0]) Print the first extended textual header: >>> print(f.text[1]) Print a textual header line-by-line: >>> # using zip, from the zip documentation >>> text = str(f.text[0]) >>> lines = map(''.join, zip( *[iter(text)] * 80)) >>> for line in lines: ... print(line) ... """ try: i = self.wrapindex(i) return self.filehandle.gettext(i) except TypeError: def gen(): for j in range(*i.indices(len(self))): yield self.filehandle.gettext(j) return gen() def __setitem__(self, i, val): """text[i] = val Write the ith text header of the file, starting at 0. If val is instance of Text or iterable of Text, value is set to be the first element of every Text Parameters ---------- i : int or slice val : str, Text or iterable if i is slice Examples -------- Write a new textual header: >>> f.text[0] = make_new_header() >>> f.text[1:3] = ["new_header1", "new_header_2"] Copy a textual header: >>> f.text[1] = g.text[0] Write a textual header based on Text: >>> f.text[1] = g.text >>> assert f.text[1] == g.text[0] >>> f.text[1:3] = [g1.text, g2.text] >>> assert f.text[1] == g1.text[0] >>> assert f.text[2] == g2.text[0] """ if isinstance(val, Text): self[i] = val[0] return try: i = self.wrapindex(i) self.filehandle.puttext(i, val) except TypeError: for i, text in zip(range(*i.indices(len(self))), val): if isinstance(text, Text): text = text[0] self.filehandle.puttext(i, text) def __str__(self): msg = 'str(text) is deprecated, use explicit format instead' warnings.warn(msg, DeprecationWarning) return '\n'.join(map(''.join, zip(*[iter(str(self[0]))] * 80))) segyio-1.8.3/python/segyio/tracefield.py0000664000372000037200000001603413407674361017737 0ustar travistravisfrom . import Enum class TraceField(Enum): """Trace header field enumerator See also ------- segyio.su : Seismic unix aliases for header fields """ TRACE_SEQUENCE_LINE = 1 TRACE_SEQUENCE_FILE = 5 FieldRecord = 9 TraceNumber = 13 EnergySourcePoint = 17 CDP = 21 CDP_TRACE = 25 TraceIdentificationCode = 29 NSummedTraces = 31 NStackedTraces = 33 DataUse = 35 offset = 37 ReceiverGroupElevation = 41 SourceSurfaceElevation = 45 SourceDepth = 49 ReceiverDatumElevation = 53 SourceDatumElevation = 57 SourceWaterDepth = 61 GroupWaterDepth = 65 ElevationScalar = 69 SourceGroupScalar = 71 SourceX = 73 SourceY = 77 GroupX = 81 GroupY = 85 CoordinateUnits = 89 WeatheringVelocity = 91 SubWeatheringVelocity = 93 SourceUpholeTime = 95 GroupUpholeTime = 97 SourceStaticCorrection = 99 GroupStaticCorrection = 101 TotalStaticApplied = 103 LagTimeA = 105 LagTimeB = 107 DelayRecordingTime = 109 MuteTimeStart = 111 MuteTimeEND = 113 TRACE_SAMPLE_COUNT = 115 TRACE_SAMPLE_INTERVAL = 117 GainType = 119 InstrumentGainConstant = 121 InstrumentInitialGain = 123 Correlated = 125 SweepFrequencyStart = 127 SweepFrequencyEnd = 129 SweepLength = 131 SweepType = 133 SweepTraceTaperLengthStart = 135 SweepTraceTaperLengthEnd = 137 TaperType = 139 AliasFilterFrequency = 141 AliasFilterSlope = 143 NotchFilterFrequency = 145 NotchFilterSlope = 147 LowCutFrequency = 149 HighCutFrequency = 151 LowCutSlope = 153 HighCutSlope = 155 YearDataRecorded = 157 DayOfYear = 159 HourOfDay = 161 MinuteOfHour = 163 SecondOfMinute = 165 TimeBaseCode = 167 TraceWeightingFactor = 169 GeophoneGroupNumberRoll1 = 171 GeophoneGroupNumberFirstTraceOrigField = 173 GeophoneGroupNumberLastTraceOrigField = 175 GapSize = 177 OverTravel = 179 CDP_X = 181 CDP_Y = 185 INLINE_3D = 189 CROSSLINE_3D = 193 ShotPoint = 197 ShotPointScalar = 201 TraceValueMeasurementUnit = 203 TransductionConstantMantissa = 205 TransductionConstantPower = 209 TransductionUnit = 211 TraceIdentifier = 213 ScalarTraceHeader = 215 SourceType = 217 SourceEnergyDirectionMantissa = 219 SourceEnergyDirectionExponent = 223 SourceMeasurementMantissa = 225 SourceMeasurementExponent = 229 SourceMeasurementUnit = 231 UnassignedInt1 = 233 UnassignedInt2 = 237 keys = { 'TRACE_SEQUENCE_LINE' : 1, 'TRACE_SEQUENCE_FILE' : 5, 'FieldRecord' : 9, 'TraceNumber' : 13, 'EnergySourcePoint' : 17, 'CDP' : 21, 'CDP_TRACE' : 25, 'TraceIdentificationCode' : 29, 'NSummedTraces' : 31, 'NStackedTraces' : 33, 'DataUse' : 35, 'offset' : 37, 'ReceiverGroupElevation' : 41, 'SourceSurfaceElevation' : 45, 'SourceDepth' : 49, 'ReceiverDatumElevation' : 53, 'SourceDatumElevation' : 57, 'SourceWaterDepth' : 61, 'GroupWaterDepth' : 65, 'ElevationScalar' : 69, 'SourceGroupScalar' : 71, 'SourceX' : 73, 'SourceY' : 77, 'GroupX' : 81, 'GroupY' : 85, 'CoordinateUnits' : 89, 'WeatheringVelocity' : 91, 'SubWeatheringVelocity' : 93, 'SourceUpholeTime' : 95, 'GroupUpholeTime' : 97, 'SourceStaticCorrection' : 99, 'GroupStaticCorrection' : 101, 'TotalStaticApplied' : 103, 'LagTimeA' : 105, 'LagTimeB' : 107, 'DelayRecordingTime' : 109, 'MuteTimeStart' : 111, 'MuteTimeEND' : 113, 'TRACE_SAMPLE_COUNT' : 115, 'TRACE_SAMPLE_INTERVAL' : 117, 'GainType' : 119, 'InstrumentGainConstant' : 121, 'InstrumentInitialGain' : 123, 'Correlated' : 125, 'SweepFrequencyStart' : 127, 'SweepFrequencyEnd' : 129, 'SweepLength' : 131, 'SweepType' : 133, 'SweepTraceTaperLengthStart' : 135, 'SweepTraceTaperLengthEnd' : 137, 'TaperType' : 139, 'AliasFilterFrequency' : 141, 'AliasFilterSlope' : 143, 'NotchFilterFrequency' : 145, 'NotchFilterSlope' : 147, 'LowCutFrequency' : 149, 'HighCutFrequency' : 151, 'LowCutSlope' : 153, 'HighCutSlope' : 155, 'YearDataRecorded' : 157, 'DayOfYear' : 159, 'HourOfDay' : 161, 'MinuteOfHour' : 163, 'SecondOfMinute' : 165, 'TimeBaseCode' : 167, 'TraceWeightingFactor' : 169, 'GeophoneGroupNumberRoll1' : 171, 'GeophoneGroupNumberFirstTraceOrigField': 173, 'GeophoneGroupNumberLastTraceOrigField' : 175, 'GapSize' : 177, 'OverTravel' : 179, 'CDP_X' : 181, 'CDP_Y' : 185, 'INLINE_3D' : 189, 'CROSSLINE_3D' : 193, 'ShotPoint' : 197, 'ShotPointScalar' : 201, 'TraceValueMeasurementUnit' : 203, 'TransductionConstantMantissa' : 205, 'TransductionConstantPower' : 209, 'TransductionUnit' : 211, 'TraceIdentifier' : 213, 'ScalarTraceHeader' : 215, 'SourceType' : 217, 'SourceEnergyDirectionMantissa' : 219, 'SourceEnergyDirectionExponent' : 223, 'SourceMeasurementMantissa' : 225, 'SourceMeasurementExponent' : 229, 'SourceMeasurementUnit' : 231, 'UnassignedInt1' : 233, 'UnassignedInt2' : 237, } segyio-1.8.3/python/examples/0000775000372000037200000000000013407674361015576 5ustar travistravissegyio-1.8.3/python/examples/write.py0000664000372000037200000000530413407674361017304 0ustar travistravisimport sys import segyio import numpy as np def main(): if len( sys.argv ) < 2: sys.exit("Usage: write.py [file]") filename = sys.argv[1] # the mode parameter is passed directly to C's fopen # opening the file for writing requires r+, not rw because rw would # truncate (effectively destroy) the file, and r+ would preserve the size with segyio.open( filename, "r+" ) as src: # read trace 0, then double all values trace = src.trace[0] trace *= 2 # write trace 0 back to disk src.trace[0] = trace # read trace 1, but re-use the memory for speed trace = src.trace[1] # square all values. the trace is a plain numpy array trace = np.square(trace, trace) # write the trace back to disk, but at trace 2 src.trace[2] = trace # read every other trace, from 10 through 20 # then write them to every third step from 40 through 52 # i.e. 40, 43, 46... # slices yield a generator, so only one numpy array is created for tr, i in zip(src.trace[10:20:2], range(2,13,3)): src.trace[i] = tr # iterate over all traces in a file. this is a generator with a shared # buffer, so it's quite efficient tracesum = 0 for tr in src.trace: # accumulate the traces' 30th value tracesum += tr[30] print("Trace sum: {}".format(tracesum)) # write the iline at 2 to the iline at 3 sum3 = np.sum(src.iline[3]) src.iline[2] = src.iline[3] # flush to make sure our changes to the file are visible src.flush() sum2 = np.sum(src.iline[2]) print("Accumulates of inlines 2 and 3: {} -- {}".format(sum2, sum3)) # ilines too are plain numpy ndarrays, with trace-major addressing # i.e. iline[2,40] would be yield trace#2's 40th value iline = src.iline[2] # since ilines are numpy arrays they also support numpy operations iline = np.add(iline, src.iline[4]) # lines too have generator support, so we accumulate the 2nd trace's # 22nd value. linesum = 0 for line in src.iline: linesum += line[2,22] print("Inline sum: {}".format(linesum)) # xline access is identical to iline access linesum = 0 for line in src.xline: linesum += line[2,22] print("Crossline sum: {}".format(linesum)) # accessing a non-existing inline will raise a KeyError try: _ = src.iline[5000] sys.exit("Was able to access non-existing inline") except KeyError as e: print(str(e)) if __name__ == '__main__': main() segyio-1.8.3/python/examples/scan_min_max.py0000664000372000037200000000127613407674361020612 0ustar travistravisimport sys import segyio import numpy as np def main(): if len(sys.argv) < 2: sys.exit("Usage: {} [segyfile] ".format(sys.argv[0])) segyfile = sys.argv[1] min_value = sys.float_info.max max_value = sys.float_info.min with segyio.open(segyfile) as f: for trace in f.trace: local_min = np.nanmin(trace) local_max = np.nanmax(trace) if np.isfinite(local_min): min_value = min(local_min, min_value) if np.isfinite(local_max): max_value = max(local_max, max_value) print("min: {}".format(min_value)) print("max: {}".format(max_value)) if __name__ == '__main__': main() segyio-1.8.3/python/examples/make-file.py0000664000372000037200000000424713407674361020011 0ustar travistravisimport sys import numpy as np import segyio def main(): if len(sys.argv) < 7: sys.exit("Usage: {} [file] [samples] [first iline] [last iline] [first xline] [last xline]".format(sys.argv[0])) spec = segyio.spec() filename = sys.argv[1] # to create a file from nothing, we need to tell segyio about the structure of # the file, i.e. its inline numbers, crossline numbers, etc. You can also add # more structural information, but offsets etc. have sensible defautls. This is # the absolute minimal specification for a N-by-M volume spec.sorting = 2 spec.format = 1 spec.samples = range(int(sys.argv[2])) spec.ilines = range(*map(int, sys.argv[3:5])) spec.xlines = range(*map(int, sys.argv[5:7])) with segyio.create(filename, spec) as f: # one inline consists of 50 traces # which in turn consists of 2000 samples start = 0.0 step = 0.00001 # fill a trace with predictable values: left-of-comma is the inline # number. Immediately right of comma is the crossline number # the rightmost digits is the index of the sample in that trace meaning # looking up an inline's i's jth crosslines' k should be roughly equal # to i.j0k trace = np.arange(start = start, stop = start + step * len(spec.samples), step = step, dtype = np.single) # one inline is N traces concatenated. We fill in the xline number line = np.concatenate([trace + (xl / 100.0) for xl in spec.xlines]) line = line.reshape( (len(spec.xlines), len(spec.samples)) ) # write the line itself to the file # write the inline number in all this line's headers for ilno in spec.ilines: f.iline[ilno] = (line + ilno) f.header.iline[ilno] = { segyio.TraceField.INLINE_3D: ilno, segyio.TraceField.offset: 1 } # then do the same for xlines for xlno in spec.xlines: f.header.xline[xlno] = { segyio.TraceField.CROSSLINE_3D: xlno } if __name__ == '__main__': main() segyio-1.8.3/python/examples/about.py0000664000372000037200000000360513407674361017266 0ustar travistravisimport sys from segyio import TraceField import segyio def list_byte_offset_names(): print("Available offsets and their corresponding byte value:") for x in TraceField.enums(): print(" {}: {}".format(str(x), x)) if __name__ == '__main__': if len(sys.argv) < 4: list_byte_offset_names() sys.exit("Usage: about.py [file] [inline] [crossline]") # we need a way to convert from run-time inline/crossline argument (as # text) to the internally used TraceField enum. Make a string -> TraceField # map and look up into that. this dictionary comprehension creates that fieldmap = {str(x).lower(): x for x in TraceField.enums()} filename = sys.argv[1] inline_name, crossline_name = sys.argv[2].lower(), sys.argv[3].lower() # exit if inline or crossline are unknown if inline_name not in fieldmap: list_byte_offset_names() sys.exit("Unknown inline field '{}'".format(sys.argv[2])) if crossline_name not in fieldmap: list_byte_offset_names() sys.exit("Unknown crossline field '{}'".format(sys.argv[3])) inline, crossline = fieldmap[inline_name], fieldmap[crossline_name] with segyio.open(filename, "r", inline, crossline) as f: print("About '{}':".format(filename)) print("Format type: {}".format(f.format)) print("Offset count: {}".format(f.offsets)) print("ilines: {}".format(", ".join(map(str, f.ilines)))) print("xlines: {}".format(", ".join(map(str, f.xlines)))) print("+------+") with segyio.open(filename, "r", crossline, inline) as f: # with swapped inline/crossline print("About '{}':".format(filename)) print("Format type: {}".format(f.format)) print("Offset count: {}".format(f.offsets)) print("ilines: {}".format(", ".join(map(str, f.ilines)))) print("xlines: {}".format(", ".join(map(str, f.xlines)))) segyio-1.8.3/python/examples/make-ps-file.py0000664000372000037200000000500413407674361020421 0ustar travistravisimport sys import numpy as np import segyio def main(): if len(sys.argv) < 9: sys.exit(" ".join(["Usage: {} [file] [samples]", "[first iline] [last iline]", "[first xline] [last xline]", "[first offset] [last offset]"] ).format(sys.argv[0])) spec = segyio.spec() filename = sys.argv[1] # to create a file from nothing, we need to tell segyio about the structure of # the file, i.e. its inline numbers, crossline numbers, etc. You can also add # more structural information, This is the absolute minimal specification for a # N-by-M volume with K offsets volume spec.sorting = 2 spec.format = 1 spec.samples = range(int(sys.argv[2])) spec.ilines = range(*map(int, sys.argv[3:5])) spec.xlines = range(*map(int, sys.argv[5:7])) spec.offsets = range(*map(int, sys.argv[7:9])) if len(spec.offsets) == 0: spec.offsets = [1] with segyio.create(filename, spec) as f: # one inline consists of 50 traces # which in turn consists of 2000 samples start = 0.0 step = 0.00001 # fill a trace with predictable values: left-of-comma is the inline # number. Immediately right of comma is the crossline number # the rightmost digits is the index of the sample in that trace meaning # looking up an inline's i's jth crosslines' k should be roughly equal # to (offset*100) + i.j0k. trace = np.arange(start = start, stop = start + step * len(spec.samples), step = step, dtype = np.single) nx, no = len(spec.xlines), len(spec.offsets) # one inline is N traces concatenated. We fill in the xline number line = np.concatenate([trace + (xl / 100.0) for xl in spec.xlines]) line = line.reshape( (nx, len(spec.samples)) ) for ilindex, ilno in enumerate(spec.ilines): iline = line + ilno for tr, xlno in enumerate(spec.xlines): for offset_index, offset in enumerate(spec.offsets): ix = (ilindex * nx * no) + (tr * no) + offset_index f.trace[ix] = iline[tr] + (offset * 100) f.header[ix] = { segyio.TraceField.INLINE_3D: ilno, segyio.TraceField.CROSSLINE_3D: xlno, segyio.TraceField.offset: offset } if __name__ == '__main__': main() segyio-1.8.3/python/examples/make-multiple-text.py0000664000372000037200000000076513407674361021710 0ustar travistravisimport sys import segyio def main(): if len(sys.argv) < 2: sys.exit("Usage: make-multiple-text.py [file]") filename = sys.argv[1] spec = segyio.spec() spec.sorting = 2 spec.format = 1 spec.samples = [1] spec.ilines = [1] spec.xlines = [1] spec.ext_headers = 4 with segyio.create(filename, spec) as f: for i in range(1, spec.ext_headers + 1): f.text[i] = f.text[0] f.trace[0] = [0] if __name__ == '__main__': main() segyio-1.8.3/python/examples/sorting-permutation.py0000664000372000037200000000606313407674361022207 0ustar travistravisimport sys import os import shutil import segyio def pathjoin( prefix, path): directory, base = os.path.split(path) pref, suff = os.path.splitext(base) filename = pref + '-' + prefix + suff return os.path.join(directory, filename) # This script reverse the traces for a given file, by iline, xline and offset in # all combinations of the three. def main(): if len(sys.argv) < 2: sys.exit("Usage: {} [source-file] [destination-file]".format(sys.argv[0])) sourcefile = sys.argv[1] destfile = sys.argv[2] if len(sys.argv) > 2 else sourcefile for suf in ['dec-il-xl-off', 'dec-il-inc-xl-off', 'dec-xl-inc-il-off', 'dec-il-xl-inc-off', 'dec-il-off-inc-xl', 'dec-xl-off-inc-il', 'dec-off-inc-il-xl']: fname = pathjoin(suf, destfile) shutil.copyfile(sourcefile, fname) with segyio.open(sourcefile) as src, segyio.open(fname, 'r+') as dst: for i in range(1 + src.ext_headers): dst.text[i] = src.text[i] dst.bin = src.bin dst.trace = src.trace dst.header = src.header with segyio.open(sourcefile) as src: with segyio.open(pathjoin("dec-il-xl-off", destfile), 'r+') as dst: dst.header = src.header[::-1] dst.trace = src.trace[::-1] with segyio.open(sourcefile) as src: with segyio.open(pathjoin("dec-il-inc-xl-off", destfile), 'r+') as dst: dst.header.iline[::, ::] = src.header.iline[::-1, ::] dst.iline[::, ::] = src.iline[::-1, ::] with segyio.open(sourcefile) as src: with segyio.open(pathjoin("dec-xl-inc-il-off", destfile), 'r+') as dst: dst.header.xline[::, ::] = src.header.xline[::-1, ::] dst.xline[::, ::] = src.xline[::-1, ::] with segyio.open(sourcefile) as src: with segyio.open(pathjoin("dec-il-xl-inc-off", destfile), 'r+') as dst: dst.header = src.header[::-1] dst.trace = src.trace[::-1] for i in range(0, len(dst.trace), 2): dst.trace[i], dst.trace[i + 1] = dst.trace[i + 1], dst.trace[i] dst.header[i], dst.header[i + 1] = dst.header[i + 1], dst.header[i] with segyio.open(sourcefile) as src: with segyio.open(pathjoin("dec-il-off-inc-xl", destfile), 'r+') as dst: dst.header.iline[::, ::] = src.header.iline[::-1, ::-1] dst.iline[::, ::] = src.iline[::-1, ::-1] with segyio.open(sourcefile) as src: with segyio.open(pathjoin("dec-xl-off-inc-il", destfile), 'r+') as dst: dst.header.iline[::, ::] = src.header.iline[::-1, ::-1] dst.header.xline[::, ::] = src.header.xline[::-1, ::-1] dst.iline[::, ::] = src.iline[::-1, ::] with segyio.open(sourcefile) as src: with segyio.open(pathjoin("dec-off-inc-il-xl", destfile), 'r+') as dst: dst.header.xline[::, ::] = src.header.xline[::, ::-1] dst.xline[::, ::] = src.xline[::, ::-1] if __name__ == '__main__': main() segyio-1.8.3/python/examples/copy-sub-cube.py0000664000372000037200000000260113407674361020624 0ustar travistravisimport sys import segyio # this program creates a new subcube, taking the first 5 lines in both # directions, and reduces the trace size to 20 samples def main(): if len(sys.argv) < 3: sys.exit("Usage: {} [source-file] [destination-file]".format(sys.argv[0])) sourcefile = sys.argv[1] destfile = sys.argv[2] with segyio.open(sourcefile) as src: spec = segyio.spec() spec.sorting = int(src.sorting) spec.format = int(src.format) spec.samples = range(50) spec.ilines = src.ilines[:5] spec.xlines = src.xlines[:5] with segyio.create(destfile, spec) as dst: # Copy all textual headers, including possible extended for i in range(1 + src.ext_headers): dst.text[i] = src.text[i] # copy the binary header, then insert the modifications needed for # the new shape dst.bin = src.bin dst.bin = { segyio.BinField.Samples: 50, segyio.BinField.Traces: 5 * 5 } # Copy all headers in the new inlines. Since we know we're copying # the five first we don't have to take special care to update # headers dst.header.iline = src.header.iline # the copy traces (in line mode) dst.iline = src.iline if __name__ == '__main__': main() segyio-1.8.3/python/examples/make-rotated-copies.py0000664000372000037200000000620013407674361022003 0ustar travistravisimport sys import os import shutil import itertools as itr import segyio import segyio.su as su def product(f): return itr.product(range(len(f.ilines)), range(len(f.xlines))) def pathjoin(prefix, path): dir, base = os.path.split(path) return os.path.join(dir, '-'.join((prefix, base))) # this program copies the source-file and creates eight copies, each with a # modified set of CDP-X and CDP-Y coordinates, rotating the field around the # north (increasing CDP-Y) axis. def main(): if len(sys.argv) < 2: sys.exit("Usage: {} [source-file] [destination-file]".format(sys.argv[0])) srcfile = sys.argv[1] dstfile = sys.argv[2] if len(sys.argv) > 2 else srcfile for pre in ['normal', 'acute', 'right', 'obtuse', 'straight', 'reflex', 'left', 'inv-acute']: fname = pathjoin(pre, dstfile) shutil.copyfile(srcfile, fname) with segyio.open(srcfile) as src, segyio.open(fname, 'r+') as dst: for i in range(1 + src.ext_headers): dst.text[i] = src.text[i] dst.bin = src.bin dst.trace = src.trace dst.header = src.header with segyio.open(pathjoin('normal', dstfile), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = x trh[su.cdpy] = y trh[su.scalco] = 10 with segyio.open(pathjoin('acute', dstfile), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[y + x * len(src.ilines)] trh[su.cdpx] = x + y trh[su.cdpy] = (100 - x) + y trh[su.scalco] = -10 with segyio.open(pathjoin('right', dstfile), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = y trh[su.cdpy] = 100 - x trh[su.scalco] = 1 with segyio.open(pathjoin('obtuse', dstfile), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = (100 - x) + y trh[su.cdpy] = (100 - x) - y trh[su.scalco] = 2 with segyio.open(pathjoin('straight', dstfile), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = 100 - x trh[su.cdpy] = 100 - y trh[su.scalco] = -7 with segyio.open(pathjoin('reflex', dstfile), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = 100 - (x + y) trh[su.cdpy] = 100 + (x - y) trh[su.scalco] = 7 with segyio.open(pathjoin('left', dstfile), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = 100 - y trh[su.cdpy] = x trh[su.scalco] = 21 with segyio.open(pathjoin('inv-acute', dstfile), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = 100 + x - y trh[su.cdpy] = x + y trh[su.scalco] = 100 if __name__ == '__main__': main() segyio-1.8.3/python/docs/0000775000372000037200000000000013407674361014710 5ustar travistravissegyio-1.8.3/python/docs/segyio.rst0000664000372000037200000000470613407674361016750 0ustar travistravisOpen and create =============== .. autofunction:: segyio.open .. autofunction:: segyio.su.open .. autofunction:: segyio.create File handle =========== .. autoclass:: segyio.SegyFile() :member-order: groupwise Addressing ========== .. currentmodule:: segyio Data trace ---------- .. autoclass:: segyio.trace.Trace() :special-members: __getitem__, __setitem__, __len__, __contains__, __iter__ .. autoclass:: segyio.trace.RawTrace() :special-members: __getitem__, __setitem__, __len__, __contains__, __iter__ .. autoclass:: segyio.trace.RefTrace() :special-members: __getitem__, __setitem__, __len__, __contains__, __iter__ Trace header and attributes --------------------------- .. autoclass:: segyio.trace.Header() :special-members: __getitem__, __setitem__, __len__, __contains__, __iter__ .. autoclass:: segyio.trace.Attributes() :special-members: __getitem__, __setitem__, __len__, __contains__, __iter__ Data line --------- .. autoclass:: segyio.line.Line() :special-members: __getitem__, __setitem__, __len__, __contains__, __iter__ Line header ----------- .. autoclass:: segyio.line.HeaderLine() :special-members: __getitem__, __setitem__, __len__, __contains__, __iter__ Gather ------ .. autoclass:: segyio.gather.Gather() :special-members: __getitem__ Depth ----- .. autoclass:: segyio.depth.Depth() :special-members: __getitem__, __setitem__, __len__, __contains__, __iter__ Text ---- .. autoclass:: segyio.trace.Text() :special-members: __getitem__, __setitem__, __len__, __contains__, __iter__ Trace and binary header ======================= .. autoclass:: segyio.field.Field() :special-members: __getitem__, __setitem__, __delitem__, __len__, __contains__, __iter__ Tools ===== .. automodule:: segyio.tools :members: :undoc-members: :show-inheritance: Constants ========= Trace header keys ----------------- .. autoclass:: segyio.TraceField :members: :undoc-members: :member-order: bysource Binary header keys ------------------ .. autoclass:: segyio.BinField :members: :undoc-members: :member-order: bysource Seismic Unix keys ----------------- .. automodule:: segyio.su.words :members: :undoc-members: :member-order: bysource Sorting and formats ------------------- .. autoclass:: segyio.TraceSortingFormat :members: :undoc-members: :member-order: bysource .. autoclass:: segyio.SegySampleFormat :members: :undoc-members: :member-order: bysource segyio-1.8.3/python/docs/conf.py0000664000372000037200000002642013407674361016213 0ustar travistravis# -*- coding: utf-8 -*- # # segyio documentation build configuration file, created by # sphinx-quickstart on Sat Mar 17 18:42:51 2018. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) import os import sys sys.path.insert(0, os.path.abspath("../")) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.5' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx.ext.autosummary', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.imgmath', ] autosummary_generate = True add_module_names = False # sphinx 1.8 deprecates autodoc_default_flags. docs should be buildable with # warnings-as-errors, but the docs really don't require more than sphinx 1.5. # use the new autodoc config if built with >= 1.8 # # ref http://luc.lino-framework.org/blog/2018/0821.html from distutils.version import LooseVersion import sphinx if LooseVersion(sphinx.__version__) < LooseVersion("1.8"): autodoc_default_flags = ['members', 'inherited-members'] else: autodoc_default_options = { 'members': None, 'inherited-members': None, } # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The encoding of source files. # # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'segyio' copyright = u'2018, Equinor' author = u'Equinor' import segyio # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = segyio.__version__ # if the docs are built without actually building segyio (what readthedocs # does), the version string will fall back to '0.0.0'. but since readthedocs # (and maybe other jobs that builds doc) often fetch from git, they can fall # back to also trying git-describe themselves. if version == '0.0.0': try: # static analysis flags the subproces module as a potential security # problem, but this takes no user input and should be safe from subprocess import check_output # nosec version = str(check_output(['git', 'describe']).strip()) # nosec finally: # couldn't run git-describe - fall back to 0.0.0 and accept that we # won't get reasonable version numbers automatically pass # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # # today = '' # # Else, today_fmt is used as the format for a strftime call. # # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The reST default role (used for this markup: `text`) to use for all # documents. # # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # # html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. # " v documentation" by default. # # html_title = u'segyio v1.5.1' # A shorter title for the navigation bar. Default is the same as html_title. # # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # # html_logo = None # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # # html_extra_path = [] # If not None, a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. # The empty string is equivalent to '%b %d, %Y'. # # html_last_updated_fmt = None # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # # html_additional_pages = {} # If false, no module index is generated. # # html_domain_indices = True # If false, no index is generated. # # html_use_index = True # If true, the index is split into individual pages for each letter. # # html_split_index = False # If true, links to the reST sources are added to the pages. # # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' # # html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # 'ja' uses this config value. # 'zh' user can custom change `jieba` dictionary path. # # html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. # # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = 'segyiodoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'segyio.tex', u'segyio Documentation', u'Equinor', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # # latex_use_parts = False # If true, show page references after internal links. # # latex_show_pagerefs = False # If true, show URL addresses after external links. # # latex_show_urls = False # Documents to append as an appendix to all manuals. # # latex_appendices = [] # It false, will not define \strong, \code, itleref, \crossref ... but only # \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added # packages. # # latex_keep_old_macro_names = True # If false, no module index is generated. # # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'segyio', u'segyio Documentation', [author], 1) ] # If true, show URL addresses after external links. # # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'segyio', u'segyio Documentation', author, 'segyio', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. # # texinfo_appendices = [] # If false, no module index is generated. # # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # # texinfo_no_detailmenu = False # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { 'https://docs.python.org/': None, 'https://docs.scipy.org/doc/numpy/': None, } segyio-1.8.3/python/docs/index.rst0000664000372000037200000000067413407674361016560 0ustar travistravis.. segyio documentation master file, created by sphinx-quickstart on Sat Mar 17 18:42:51 2018. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. ******************** segyio documentation ******************** API reference ============= .. toctree:: :maxdepth: 3 segyio Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` segyio-1.8.3/python/CMakeLists.txt0000664000372000037200000001514113407674361016522 0ustar travistravisproject(segyio-python) if (REQUIRE_PYTHON) set(BUILD_PYTHON ON) endif() if (NOT BUILD_PYTHON) return() endif() find_package(PythonInterp REQUIRED) if (NOT PYTHON_EXECUTABLE AND REQUIRE_PYTHON) message(SEND_ERROR "Could not find python executable") return() endif() if (NOT PYTHON_EXECUTABLE) message(WARNING "Could not find python - skipping python bindings") return() endif() if (PYTHON_INSTALL_LAYOUT) set(setup-install-layout --install-layout ${PYTHON_INSTALL_LAYOUT}) endif() set(python ${PYTHON_EXECUTABLE}) if (NOT WIN32) # setuptools on microsoft compilers doesn't support the --library-dir or # --build-dir flag and crashes, so only pass it on non-microsoft platforms set(setup-py-libdir build_ext --rpath $ --library-dirs $) set(install-no-rpath install_lib --build-dir build/install) set(build-no-rpath --library-dirs $ build --build-lib build/install) else () set(copy-dll-to-src ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_SOURCE_DIR}/segyio/$) endif () set(setup-py ${CMAKE_SOURCE_DIR}/setup.py) add_custom_target( segyio-python ALL COMMENT "Building python library with setup.py" SOURCES ${setup-py} DEPENDS ${setup-py} VERBATIM # copy the examples to have them runnable from a relative directory, so # that a locally-installed segyio can be imported COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/examples . # do the same to tests. running through setup.py test is *very* slow, so # invoke unittest manually from the build directory. more importantly, # setup.py test will pollute the source directory with egg info and # extensions, which is unacceptable in a cmake world COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/test test # setuptools on windows breaks spectacularly when the library isn't # available in the same directory, and build_ext --library-dirs is not # support on msvc is not supported, so we must copy out the libsegyio core # object and put it here COMMAND ${CMAKE_COMMAND} -E copy $ $ COMMAND ${CMAKE_COMMAND} -E copy $ $ # on windows, copy the freshly-built dll to the source directory. this # voilates the cmake spirit (as does the version.py writing from # setuptools-scm), but there's no auditwheel like tool to help fix the # wheel, and the dll must still be bundled in order to make the package # work. it's paired with package_data in setup.py. this is necessary # because setup.py assumes all files to bundled with the package are # relative downwards and in the package itself, with poor support for # grabbing other files and adding to it later. COMMAND ${copy-dll-to-src} # install the lib in the build-dir so that the examples can load that from # current working dir COMMAND ${python} ${setup-py} ${setup-py-libdir} install_lib -d . # to maintain good make && make install behaviour, the extension is built # twice, one with rpath (for testing and build-dir-local) and one for # installation COMMAND ${python} ${setup-py} build_ext ${build-no-rpath} ) add_dependencies(segyio-python segyio) # write egg_info to the build dir in order not to pollute the source directory # and install as if it was through some other distro by using single-version, # so that install won't die on possibly missing pythonpath # setup.py install doesn't respect DESTDIR, so "force" it by changing the # --root if DESTDIR is passed install(CODE " if (DEFINED ENV{DESTDIR}) get_filename_component(abs-destdir \"\$ENV{DESTDIR}\" ABSOLUTE) set(root_destdir --root=\${abs-destdir}) endif() execute_process(COMMAND ${python} ${setup-py} install_egg_info --install-dir . egg_info --egg-base . ${install-no-rpath} install --prefix=${CMAKE_INSTALL_PREFIX} --single-version-externally-managed --record installed-files ${setup-install-layout} \${root_destdir} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )") option(BUILD_PYDOC "Build python documentation" OFF) if(BUILD_DOC) set(BUILD_PYDOC ON) endif() if(BUILD_PYDOC) find_program(sphinx sphinx-build) if(NOT sphinx) message(WARNING "Could not find sphinx, skipping python documentation") set(BUILD_PYDOC OFF) endif() endif() if(BUILD_PYDOC AND sphinx) # use the -d argument to avoid putting cache dir in docs/, because that # directory will be install'd add_custom_target(pydoc COMMAND ${sphinx} -d ${CMAKE_CURRENT_BINARY_DIR}/.doctrees ${SPHINX_ARGS} ${CMAKE_CURRENT_SOURCE_DIR}/docs ${CMAKE_CURRENT_BINARY_DIR}/docs DEPENDS docs/conf.py docs/index.rst docs/segyio.rst COMMENT "Building python documentation with sphinx" ) add_dependencies(doc pydoc) install( DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs/ DESTINATION ${CMAKE_INSTALL_DATADIR}/doc/segyio ) endif() if(NOT BUILD_TESTING) return() endif() file(GLOB sgys ${testdata}/*.sgy ${testdata}/*.su) foreach (sgy ${sgys}) get_filename_component(fl ${sgy} NAME) configure_file(${sgy} test-data/${fl} COPYONLY) endforeach () set(pytest ${python} -m pytest) add_test(NAME python.unit COMMAND ${pytest} test/) configure_file(${testdata}/small.sgy test-data/write.sgy COPYONLY) add_test(NAME python.example.about COMMAND ${python} about.py test-data/small.sgy INLINE_3D CROSSLINE_3D) add_test(NAME python.example.write COMMAND ${python} write.py test-data/write.sgy) add_test(NAME python.example.makefile COMMAND ${python} make-file.py test-data/large-file.sgy 20 1 20 1 20) add_test(NAME python.example.makepsfile COMMAND ${python} make-ps-file.py test-data/small-prestack.sgy 10 1 5 1 4 1 3) add_test(NAME python.example.subcube COMMAND ${python} copy-sub-cube.py test-data/small.sgy test-data/copy.sgy) add_test(NAME python.example.rotate COMMAND ${python} make-rotated-copies.py test-data/small.sgy ex-rotate.sgy) add_test(NAME python.example.scan_min_max COMMAND ${python} scan_min_max.py test-data/small.sgy) add_test(NAME python.example.multi-text COMMAND ${python} make-multiple-text.py test-data/multi-text.sgy) segyio-1.8.3/python/test/0000775000372000037200000000000013407674361014737 5ustar travistravissegyio-1.8.3/python/test/segyio_c.py0000664000372000037200000003661013407674361017120 0ustar travistravisfrom __future__ import absolute_import import os import numpy import pytest from pytest import approx from . import tmpfiles import segyio import segyio._segyio as _segyio def test_binary_header_size(): assert 400 == _segyio.binsize() def test_textheader_size(): assert 3200 == _segyio.textsize() def test_open_non_existing_file(): with pytest.raises(IOError): _ = _segyio.segyiofd("non-existing", "r", 0) def test_close_non_existing_file(): with pytest.raises(TypeError): _segyio.segyiofd.close(None) def test_open_and_close_file(): f = _segyio.segyiofd("test-data/small.sgy", "r", 0) f.close() def test_open_flush_and_close_file(): f = _segyio.segyiofd("test-data/small.sgy", "r", 0) f.flush() f.close() with pytest.raises(IOError): f.flush() def test_read_text_header_mmap(): test_read_text_header(True) def test_read_text_header(mmap=False): f = _segyio.segyiofd("test-data/small.sgy", "r", 0) if mmap: f.mmap() lines = { 1: "DATE: 2016-09-19", 2: "AN INCREASE IN AMPLITUDE EQUALS AN INCREASE IN ACOUSTIC IMPEDANCE", 3: "Written by libsegyio (python)", 11: "TRACE HEADER POSITION:", 12: " INLINE BYTES 189-193 | OFFSET BYTES 037-041", 13: " CROSSLINE BYTES 193-197 |", 15: "END EBCDIC HEADER" } rows = segyio.create_text_header(lines) rows = bytearray(rows, 'ascii') # mutable array of bytes rows[-1] = 128 # \x80 actual_text_header = bytes(rows) assert f.gettext(0) == actual_text_header with pytest.raises(Exception): _segyio.read_texthdr(None, 0) f.close() @tmpfiles("test-data/small.sgy") def test_write_text_header_mmap(tmpdir): f = get_instance_segyiofd(tmpdir) write_text_header(f, True) @tmpfiles("test-data/small.sgy") def test_write_text_header(tmpdir): f = get_instance_segyiofd(tmpdir) write_text_header(f, False) def write_text_header(f, mmap): if mmap: f.mmap() f.puttext(0, "") textheader = f.gettext(0) textheader = textheader.decode('ascii') assert textheader == "" * 3200 f.puttext(0, "yolo" * 800) textheader = f.gettext(0) textheader = textheader.decode('ascii') # Because in Python 3.5 bytes are not comparable to strings assert textheader == "yolo" * 800 f.close() def get_instance_segyiofd(tmpdir, file_name="small.sgy", mode="r+", samples = None, tracecount = None, ): path = str(tmpdir) f = os.path.join(path, file_name) if samples is not None: return _segyio.segyiofd(f, mode, 0).segymake(samples, tracecount) else: return _segyio.segyiofd(f, mode, 0).segyopen() @tmpfiles("test-data/small.sgy") def test_read_and_write_binary_header(tmpdir): f = get_instance_segyiofd(tmpdir) read_and_write_binary_header(f, False) @tmpfiles("test-data/small.sgy") def test_read_and_write_binary_header_mmap(tmpdir): f = get_instance_segyiofd(tmpdir) read_and_write_binary_header(f, True) def read_and_write_binary_header(f, mmap): if mmap: f.mmap() binary_header = f.getbin() with pytest.raises(ValueError): f.putbin("Buffer too small") f.putbin(binary_header) f.close() def test_read_binary_header_fields_mmap(): test_read_binary_header_fields(True) def test_read_binary_header_fields(mmap=False): f = _segyio.segyiofd("test-data/small.sgy", "r", 0) if mmap: f.mmap() binary_header = f.getbin() with pytest.raises(TypeError): _ = _segyio.getfield([], 0) with pytest.raises(KeyError): _ = _segyio.getfield(binary_header, -1) assert _segyio.getfield(binary_header, 3225) == 1 assert _segyio.getfield(binary_header, 3221) == 50 f.close() def test_line_metrics_mmap(): test_line_metrics(True) def test_line_metrics(mmap=False): f = _segyio.segyiofd("test-data/small.sgy", "r", 0).segyopen() if mmap: f.mmap() ilb = 189 xlb = 193 metrics = f.metrics() metrics.update(f.cube_metrics(ilb, xlb)) f.close() sorting = metrics['sorting'] trace_count = metrics['tracecount'] inline_count = metrics['iline_count'] crossline_count = metrics['xline_count'] offset_count = metrics['offset_count'] metrics = _segyio.line_metrics(sorting, trace_count, inline_count, crossline_count, offset_count) assert metrics['xline_length'] == 5 assert metrics['xline_stride'] == 5 assert metrics['iline_length'] == 5 assert metrics['iline_stride'] == 1 # (sorting, trace_count, inline_count, crossline_count, offset_count) metrics = _segyio.line_metrics(1, 15, 3, 5, 1) assert metrics['xline_length'] == 3 assert metrics['xline_stride'] == 1 assert metrics['iline_length'] == 5 assert metrics['iline_stride'] == 3 metrics = _segyio.line_metrics(2, 15, 3, 5, 1) assert metrics['xline_length'] == 3 assert metrics['xline_stride'] == 5 assert metrics['iline_length'] == 5 assert metrics['iline_stride'] == 1 def test_metrics_mmap(): test_metrics(True) def test_metrics(mmap=False): f = _segyio.segyiofd("test-data/small.sgy", "r", 0).segyopen() if mmap: f.mmap() ilb = 189 xlb = 193 with pytest.raises(IndexError): metrics = f.metrics() metrics.update(f.cube_metrics(ilb + 1, xlb)) metrics = f.metrics() metrics.update(f.cube_metrics(ilb, xlb)) assert metrics['trace0'] == _segyio.textsize() + _segyio.binsize() assert metrics['samplecount'] == 50 assert metrics['format'] == 1 assert metrics['trace_bsize'] == 200 assert metrics['sorting'] == 2 # inline sorting = 2, crossline sorting = 1 assert metrics['tracecount'] == 25 assert metrics['offset_count'] == 1 assert metrics['iline_count'] == 5 assert metrics['xline_count'] == 5 f.close() def test_indices_mmap(): test_indices(True) def test_indices(mmap=False): f = _segyio.segyiofd("test-data/small.sgy", "r", 0).segyopen() if mmap: f.mmap() ilb = 189 xlb = 193 metrics = f.metrics() dmy = numpy.zeros(2, dtype=numpy.intc) dummy_metrics = {'xline_count': 2, 'iline_count': 2, 'offset_count': 1} with pytest.raises(TypeError): f.indices("-", dmy, dmy, dmy) with pytest.raises(TypeError): f.indices(dummy_metrics, 1, dmy, dmy) with pytest.raises(TypeError): f.indices(dummy_metrics, dmy, 2, dmy) with pytest.raises(TypeError): f.indices(dummy_metrics, dmy, dmy, 2) one = numpy.zeros(1, dtype=numpy.intc) two = numpy.zeros(2, dtype=numpy.intc) off = numpy.zeros(1, dtype=numpy.intc) with pytest.raises(ValueError): f.indices(dummy_metrics, one, two, off) with pytest.raises(ValueError): f.indices(dummy_metrics, two, one, off) metrics.update(f.cube_metrics(ilb, xlb)) # Happy Path iline_indexes = numpy.zeros(metrics['iline_count'], dtype=numpy.intc) xline_indexes = numpy.zeros(metrics['xline_count'], dtype=numpy.intc) offsets = numpy.zeros(metrics['offset_count'], dtype=numpy.intc) f.indices(metrics, iline_indexes, xline_indexes, offsets) assert [1, 2, 3, 4, 5] == list(iline_indexes) assert [20, 21, 22, 23, 24] == list(xline_indexes) assert [1] == list(offsets) f.close() def test_fread_trace0_mmap(): test_fread_trace0(True) def test_fread_trace0(mmap=False): f = _segyio.segyiofd("test-data/small.sgy", "r", 0).segyopen() if mmap: f.mmap() ilb = 189 xlb = 193 metrics = f.metrics() metrics.update(f.cube_metrics(ilb, xlb)) sorting = metrics['sorting'] trace_count = metrics['tracecount'] inline_count = metrics['iline_count'] crossline_count = metrics['xline_count'] offset_count = metrics['offset_count'] line_metrics = _segyio.line_metrics(sorting, trace_count, inline_count, crossline_count, offset_count) iline_indexes = numpy.zeros(metrics['iline_count'], dtype=numpy.intc) xline_indexes = numpy.zeros(metrics['xline_count'], dtype=numpy.intc) offsets = numpy.zeros(metrics['offset_count'], dtype=numpy.intc) f.indices(metrics, iline_indexes, xline_indexes, offsets) with pytest.raises(KeyError): _segyio.fread_trace0(0, len(xline_indexes), line_metrics['iline_stride'], offset_count, iline_indexes, "inline") with pytest.raises(KeyError): _segyio.fread_trace0(2, len(iline_indexes), line_metrics['xline_stride'], offset_count, xline_indexes, "crossline") value = _segyio.fread_trace0(1, len(xline_indexes), line_metrics['iline_stride'], offset_count, iline_indexes, "inline") assert value == 0 value = _segyio.fread_trace0(2, len(xline_indexes), line_metrics['iline_stride'], offset_count, iline_indexes, "inline") assert value == 5 value = _segyio.fread_trace0(21, len(iline_indexes), line_metrics['xline_stride'], offset_count, xline_indexes, "crossline") assert value == 1 value = _segyio.fread_trace0(22, len(iline_indexes), line_metrics['xline_stride'], offset_count, xline_indexes, "crossline") assert value == 2 f.close() def test_get_and_putfield(): hdr = bytearray(_segyio.thsize()) with pytest.raises(BufferError): _segyio.getfield(".", 0) with pytest.raises(TypeError): _segyio.getfield([], 0) with pytest.raises(TypeError): _segyio.putfield({}, 0, 1) with pytest.raises(KeyError): _segyio.getfield(hdr, 0) with pytest.raises(KeyError): _segyio.putfield(hdr, 0, 1) _segyio.putfield(hdr, 1, 127) _segyio.putfield(hdr, 5, 67) _segyio.putfield(hdr, 9, 19) assert _segyio.getfield(hdr, 1) == 127 assert _segyio.getfield(hdr, 5) == 67 assert _segyio.getfield(hdr, 9) == 19 @tmpfiles("test-data/small.sgy") def test_read_and_write_traceheader_mmap(tmpdir): f = get_instance_segyiofd(tmpdir) read_and_write_traceheader(f, True) @tmpfiles("test-data/small.sgy") def test_read_and_write_traceheader(tmpdir): f = get_instance_segyiofd(tmpdir) read_and_write_traceheader(f, False) def read_and_write_traceheader(f, mmap): if mmap: f.mmap() ilb = 189 xlb = 193 def mkempty(): return bytearray(_segyio.thsize()) with pytest.raises(TypeError): f.getth("+") with pytest.raises(TypeError): f.getth(0, None) trace_header = f.getth(0, mkempty()) assert _segyio.getfield(trace_header, ilb) == 1 assert _segyio.getfield(trace_header, xlb) == 20 trace_header = f.getth(1, mkempty()) assert _segyio.getfield(trace_header, ilb) == 1 assert _segyio.getfield(trace_header, xlb) == 21 _segyio.putfield(trace_header, ilb, 99) _segyio.putfield(trace_header, xlb, 42) f.putth(0, trace_header) trace_header = f.getth(0, mkempty()) assert _segyio.getfield(trace_header, ilb) == 99 assert _segyio.getfield(trace_header, xlb) == 42 f.close() def test_read_traceheaders(): f = _segyio.segyiofd("test-data/small.sgy", "r", 0).segyopen() read_traceheaders_forall(f, False) read_traceheaders_forall(f, True) read_traceheaders_foreach(f, False) read_traceheaders_foreach(f, True) f.close() def read_traceheaders_forall(f, mmap): if mmap: f.mmap() start, stop, step = 20, -1, -5 indices = range(start, stop, step) attrs = numpy.empty(len(indices), dtype=numpy.intc) field = segyio.TraceField.INLINE_3D with pytest.raises(ValueError): f.field_forall(attrs, start, stop, 0, field) buf_handle = f.field_forall(attrs, start, stop, step, field) numpy.testing.assert_array_equal(attrs, [5, 4, 3, 2, 1]) assert buf_handle is attrs def read_traceheaders_foreach(f, mmap): if mmap: f.mmap() indices = numpy.asarray([7, 4, 1, 18, 20], dtype=numpy.intc) attrs = numpy.empty(len(indices), dtype=numpy.intc) field = segyio.TraceField.CROSSLINE_3D with pytest.raises(ValueError): f.field_foreach(numpy.empty(1, dtype=numpy.intc), indices, field) buf_handle = f.field_foreach(attrs, indices, field) numpy.testing.assert_array_equal(attrs, [22, 24, 21, 23, 20]) assert buf_handle is attrs @tmpfiles("test-data/small.sgy") def test_read_and_write_trace_mmap(tmpdir): f = get_instance_segyiofd(tmpdir, "trace-wrt.sgy", "w+", samples = 25, tracecount = 100, ) read_and_write_trace(f, True) @tmpfiles("test-data/small.sgy") def test_read_and_write_trace(tmpdir): f = get_instance_segyiofd(tmpdir, "trace-wrt.sgy", "w+", samples = 25, tracecount = 100, ) read_and_write_trace(f, False) def read_and_write_trace(f, mmap): if mmap: f.mmap() buf = numpy.ones(25, dtype=numpy.single) buf[11] = 3.1415 f.puttr(0, buf) buf[:] = 42.0 f.puttr(1, buf) f.flush() buf = numpy.zeros(25, dtype=numpy.single) f.gettr(buf, 0, 1, 1) assert buf[10] == approx(1.0, abs=1e-4) assert buf[11] == approx(3.1415, abs=1e-4) f.gettr(buf, 1, 1, 1) assert sum(buf) == approx(42.0 * 25, abs=1e-4) f.close() def test_read_line(): f, metrics, iline_idx, xline_idx = read_small(False) read_line(f, metrics, iline_idx, xline_idx) def test_read_line_mmap(): f, metrics, iline_idx, xline_idx = read_small(True) read_line(f, metrics, iline_idx, xline_idx) def read_line(f, metrics, iline_idx, xline_idx): samples = metrics['samplecount'] xline_stride = metrics['xline_stride'] iline_stride = metrics['iline_stride'] offsets = metrics['offset_count'] xline_trace0 = _segyio.fread_trace0(20, len(iline_idx), xline_stride, offsets, xline_idx, "crossline") iline_trace0 = _segyio.fread_trace0(1, len(xline_idx), iline_stride, offsets, iline_idx, "inline") buf = numpy.zeros((len(iline_idx), samples), dtype=numpy.single) f.getline(xline_trace0, len(iline_idx), xline_stride, offsets, buf) assert sum(sum(buf)) == approx(800.061169624, abs=1e-6) f.getline(iline_trace0, len(xline_idx), iline_stride, offsets, buf) assert sum(sum(buf)) == approx(305.061146736, abs=1e-6) f.close() def read_small(mmap=False): f = _segyio.segyiofd("test-data/small.sgy", "r", 0).segyopen() if mmap: f.mmap() ilb = 189 xlb = 193 metrics = f.metrics() metrics.update(f.cube_metrics(ilb, xlb)) sorting = metrics['sorting'] trace_count = metrics['tracecount'] inline_count = metrics['iline_count'] crossline_count = metrics['xline_count'] offset_count = metrics['offset_count'] line_metrics = _segyio.line_metrics(sorting, trace_count, inline_count, crossline_count, offset_count) metrics.update(line_metrics) iline_indexes = numpy.zeros(metrics['iline_count'], dtype=numpy.intc) xline_indexes = numpy.zeros(metrics['xline_count'], dtype=numpy.intc) offsets = numpy.zeros(metrics['offset_count'], dtype=numpy.intc) f.indices(metrics, iline_indexes, xline_indexes, offsets) return f, metrics, iline_indexes, xline_indexes def test_fread_trace0_for_depth(): elements = list(range(25)) indices = numpy.asarray(elements, dtype=numpy.intc) for index in indices: d = _segyio.fread_trace0(index, 1, 1, 1, indices, "depth") assert d == index with pytest.raises(KeyError): _segyio.fread_trace0(25, 1, 1, 1, indices, "depth") segyio-1.8.3/python/test/tools.py0000664000372000037200000003074113407674361016456 0ustar travistravisimport numpy as np import pytest from pytest import approx from . import tmpfiles import segyio from segyio import BinField from segyio import TraceField from segyio import TraceSortingFormat from segyio import SegySampleFormat @tmpfiles("test-data/small.sgy") def test_dt_fallback(tmpdir): with segyio.open(tmpdir / 'small.sgy', "r+") as f: # Both zero f.bin[BinField.Interval] = 0 f.header[0][TraceField.TRACE_SAMPLE_INTERVAL] = 0 f.flush() fallback_dt = 4 assert segyio.dt(f, fallback_dt) == approx(fallback_dt) # dt in bin header different from first trace f.bin[BinField.Interval] = 6000 f.header[0][TraceField.TRACE_SAMPLE_INTERVAL] = 1000 f.flush() fallback_dt = 4 assert segyio.dt(f, fallback_dt) == approx(fallback_dt) @tmpfiles("test-data/small.sgy") def test_dt_no_fallback(tmpdir): dt_us = 6000 with segyio.open(tmpdir / 'small.sgy', "r+") as f: f.bin[BinField.Interval] = dt_us f.header[0][TraceField.TRACE_SAMPLE_INTERVAL] = dt_us f.flush() assert segyio.dt(f) == approx(dt_us) def test_sample_indexes(): with segyio.open("test-data/small.sgy") as f: indexes = segyio.sample_indexes(f) step = 4000.0 assert indexes == [t * step for t in range(len(f.samples))] indexes = segyio.sample_indexes(f, t0=1.5) assert indexes == [1.5 + t * step for t in range(len(f.samples))] indexes = segyio.sample_indexes(f, t0=1.5, dt_override=3.21) assert indexes == [1.5 + t * 3.21 for t in range(len(f.samples))] def test_empty_text_header_creation(): text_header = segyio.create_text_header({}) for line_no in range(0, 40): line = text_header[line_no * 80: (line_no + 1) * 80] assert line == "C{0:>2} {1:76}".format(line_no + 1, "") def test_wrap(): with segyio.open("test-data/small.sgy") as f: segyio.tools.wrap(f.text[0]) segyio.tools.wrap(f.text[0], 90) def test_values_text_header_creation(): lines = {i + 1: chr(64 + i) * 76 for i in range(40)} text_header = segyio.create_text_header(lines) for line_no in range(0, 40): line = text_header[line_no * 80: (line_no + 1) * 80] assert line == "C{0:>2} {1:76}".format(line_no + 1, chr(64 + line_no) * 76) def test_native(): with open("test-data/small.sgy", 'rb') as f, segyio.open("test-data/small.sgy") as sgy: f.read(3600 + 240) filetr = f.read(4 * len(sgy.samples)) segytr = sgy.trace[0] filetr = np.frombuffer(filetr, dtype=np.single) assert not np.array_equal(segytr, filetr) assert np.array_equal(segytr, segyio.tools.native(filetr)) def test_cube_filename(): with segyio.open("test-data/small.sgy") as f: c1 = segyio.tools.cube(f) c2 = segyio.tools.cube("test-data/small.sgy") assert np.all(c1 == c2) def test_cube_identity(): with segyio.open("test-data/small.sgy") as f: x = segyio.tools.collect(f.trace[:]) x = x.reshape((len(f.ilines), len(f.xlines), len(f.samples))) assert np.all(x == segyio.tools.cube(f)) def test_cube_identity_prestack(): with segyio.open("test-data/small-ps.sgy") as f: dims = (len(f.ilines), len(f.xlines), len(f.offsets), len(f.samples)) x = segyio.tools.collect(f.trace[:]).reshape(dims) assert np.all(x == segyio.tools.cube(f)) def test_unstructured_rotation(): with pytest.raises(ValueError): with segyio.open("test-data/small.sgy", ignore_geometry=True) as f: segyio.tools.rotation(f) def test_rotation(): names = ['normal', 'acute', 'right', 'obtuse', 'straight', 'reflex', 'left', 'inv-acute'] angles = [0.000, 0.785, 1.571, 2.356, 3.142, 3.927, 4.712, 5.498] rights = [1.571, 2.356, 3.142, 3.927, 4.712, 5.498, 0.000, 0.785] def rotation(x, **kwargs): return segyio.tools.rotation(x, **kwargs)[0] for name, angle, right in zip(names, angles, rights): src = "test-data/small.sgy".replace('/', '/' + name + '-') with segyio.open(src) as f: assert angle == approx(rotation(f), abs=1e-3) assert angle == approx(rotation(f, line='fast'), abs=1e-3) assert angle == approx(rotation(f, line='iline'), abs=1e-3) assert right == approx(rotation(f, line='slow'), abs=1e-3) assert right == approx(rotation(f, line='xline'), abs=1e-3) def test_metadata(): spec = segyio.spec() spec.ilines = [1, 2, 3, 4, 5] spec.xlines = [20, 21, 22, 23, 24] spec.samples = list(range(0, 200, 4)) spec.sorting = 2 spec.format = 1 smallspec = segyio.tools.metadata("test-data/small.sgy") assert np.array_equal(spec.ilines, smallspec.ilines) assert np.array_equal(spec.xlines, smallspec.xlines) assert np.array_equal(spec.offsets, smallspec.offsets) assert np.array_equal(spec.samples, smallspec.samples) assert spec.sorting == smallspec.sorting assert spec.format == int(smallspec.format) @tmpfiles("test-data/small.sgy") def test_resample_none(tmpdir): old = list(range(0, 200, 4)) with segyio.open(tmpdir / 'small.sgy', 'r+') as f: assert np.array_equal(old, f.samples) segyio.tools.resample(f) # essentially a no-op assert np.array_equal(old, f.samples) with segyio.open(tmpdir / 'small.sgy') as f: assert np.array_equal(old, f.samples) @tmpfiles("test-data/small.sgy") def test_resample_all(tmpdir): old = list(range(0, 200, 4)) new = list(range(12, 112, 2)) with segyio.open(tmpdir / 'small.sgy', 'r+') as f: assert np.array_equal(old, f.samples) segyio.tools.resample(f, rate=2, delay=12) assert np.array_equal(new, f.samples) with segyio.open(tmpdir / 'small.sgy') as f: assert np.array_equal(new, f.samples) @tmpfiles("test-data/small.sgy") def test_resample_rate(tmpdir): old = list(range(0, 200, 4)) new = list(range(12, 212, 4)) with segyio.open(tmpdir / 'small.sgy', 'r+') as f: assert np.array_equal(old, f.samples) segyio.tools.resample(f, delay=12) assert np.array_equal(new, f.samples) with segyio.open(tmpdir / 'small.sgy') as f: assert np.array_equal(new, f.samples) @tmpfiles("test-data/small.sgy") def test_resample_delay(tmpdir): old = list(range(0, 200, 4)) new = list(range(0, 100, 2)) with segyio.open(tmpdir / 'small.sgy', 'r+') as f: assert np.array_equal(old, f.samples) segyio.tools.resample(f, rate=2000, micro=True) assert np.array_equal(new, f.samples) with segyio.open(tmpdir / 'small.sgy') as f: assert np.array_equal(new, f.samples) def createfromany(path, data, il=189, xl=193, sample_format=1, dt=4000, delrt=0): segyio.tools.from_array(path, data, il, xl, sample_format, dt, delrt) def createfrom2d(path, data, il=189, xl=193, sample_format=1, dt=4000, delrt=0): segyio.tools.from_array2D(path, data, il, xl, sample_format, dt, delrt) def createfrom3d(path, data, il=189, xl=193, sample_format=1, dt=4000, delrt=0): segyio.tools.from_array3D(path, data, il, xl, sample_format, dt, delrt) def createfrom4d(path, data, il=189, xl=193, sample_format=1, dt=4000, delrt=0): segyio.tools.from_array4D(path, data, il, xl, sample_format, dt, delrt) @pytest.mark.parametrize("create", [createfrom2d, createfromany]) def testfrom_array_2D(tmpdir, create): fresh = str(tmpdir / 'fresh.sgy') data = np.arange(250, dtype=np.float32).reshape((10,25)) dt, delrt = 4000, 0 create(fresh, data, dt=dt, delrt=delrt) with segyio.open(fresh, 'r') as f: assert int(f.format) == SegySampleFormat.IBM_FLOAT_4_BYTE assert int(f.sorting) == TraceSortingFormat.INLINE_SORTING assert len(f.samples) == 25 assert int(f.tracecount) == 10 assert np.array_equal(f.iline[1], data) assert list(f.ilines) == [1] assert list(f.xlines) == list(range(1, 11)) assert list(f.offsets) == list(range(1, 2)) assert list(f.samples) == list( (np.arange(len(f.samples)) * dt/1000) + delrt) ilines = np.ones(10) xlines = range(1, 11) offsets = np.ones(10) assert list(f.attributes(TraceField.INLINE_3D)) == list(ilines) assert list(f.attributes(TraceField.CROSSLINE_3D)) == list(xlines) assert list(f.attributes(TraceField.offset)) == list(offsets) assert list(f.attributes(TraceField.TraceNumber)) == list(range(10)) assert list(f.attributes(TraceField.CDP_TRACE)) == list(range(10)) assert list(f.attributes(TraceField.TRACE_SAMPLE_INTERVAL)) == list( 4000 * np.ones(10)) assert list(f.attributes(TraceField.TRACE_SAMPLE_COUNT)) == list( 25 * np.ones(10)) assert list(f.attributes(TraceField.DelayRecordingTime)) == list( np.zeros(10) ) @pytest.mark.parametrize("create", [createfrom3d, createfromany]) def test_from_array3D(tmpdir, create): fresh = str(tmpdir / 'fresh.sgy') with segyio.open("test-data/small.sgy") as f: cube = segyio.cube(f) dt, delrt = 4000, 0 create(fresh, cube, dt=dt, delrt=delrt) with segyio.open(fresh) as g: assert int(g.format) == SegySampleFormat.IBM_FLOAT_4_BYTE assert int(g.sorting) == TraceSortingFormat.INLINE_SORTING assert len(g.samples) == len(f.samples) assert g.tracecount == f.tracecount assert np.array_equal(f.trace, g.trace) assert list(g.ilines) == list(range(1, 6)) assert list(g.xlines) == list(range(1, 6)) assert list(f.offsets) == list(range(1, 2)) assert list(f.samples) == list( (np.arange(len(f.samples)) * dt / 1000) + delrt) xlines = np.tile(np.arange(1, 6), 5) ilines = np.repeat(np.arange(1, 6), 5) offsets = np.ones(25) assert list(g.attributes(TraceField.INLINE_3D)) == list(ilines) assert list(g.attributes(TraceField.CROSSLINE_3D)) == list(xlines) assert list(g.attributes(TraceField.offset)) == list(offsets) assert list(g.attributes(TraceField.TraceNumber)) == list(range(25)) assert list(g.attributes(TraceField.CDP_TRACE)) == list(range(25)) assert list(g.attributes(TraceField.TRACE_SAMPLE_INTERVAL)) == list( 4000 * np.ones(25)) assert list(g.attributes(TraceField.TRACE_SAMPLE_COUNT)) == list( 50 * np.ones(25)) assert g.bin[BinField.SortingCode] == 2 @pytest.mark.parametrize("create", [createfrom4d, createfromany]) def test_from_array4D(tmpdir, create): fresh = str(tmpdir / 'fresh.sgy') data = np.repeat(np.arange(24, dtype=np.float32), 10).reshape((4,3,2,10)) dt, delrt = 4000, 0 create(fresh, data, dt=dt, delrt=delrt) with segyio.open(fresh) as f: assert int(f.format) == SegySampleFormat.IBM_FLOAT_4_BYTE assert int(f.sorting) == TraceSortingFormat.INLINE_SORTING assert len(f.samples) == 10 assert int(f.tracecount) == 24 assert list(f.ilines) == list(range(1, 5)) assert list(f.xlines) == list(range(1, 4)) assert list(f.offsets) == list(range(1, 3)) assert list(f.samples) == list( (np.arange(len(f.samples)) * dt / 1000) + delrt) iline4 = f.iline[4, 1] assert list(iline4[0, :]) == list(18*np.ones(10)) assert list(iline4[2, :]) == list(22*np.ones(10)) xline2 = f.xline[2, 2] assert list(xline2[1, :]) == list(9 * np.ones(10)) assert list(xline2[3, :]) == list(21 * np.ones(10)) ilines = np.repeat(np.arange(1, 5), 6) xlines = np.repeat(np.tile(np.arange(1, 4), 4), 2) offsets = np.tile(np.arange(1, 3), 12) assert list(f.attributes(TraceField.INLINE_3D)) == list(ilines) assert list(f.attributes(TraceField.CROSSLINE_3D)) == list(xlines) assert list(f.attributes(TraceField.offset)) == list(offsets) @pytest.mark.parametrize("create", [createfrom2d, createfrom3d, createfrom4d, createfromany]) def test_create_from_array_invalid_args(tmpdir, create): fresh = str(tmpdir / 'fresh.sgy') data = np.arange(100, dtype=np.float32) with pytest.raises(ValueError): create(fresh, data) data = "rubbish-input" with pytest.raises(ValueError): create(fresh, data) segyio-1.8.3/python/test/segyioenum.py0000664000372000037200000000057613407674361017505 0ustar travistravisfrom segyio import Enum def test_enum(): class TestEnum(Enum): ZERO = 0 ONE = 1 TWO = 2 assert TestEnum.ONE == 1 one = TestEnum(TestEnum.ONE) assert isinstance(one, TestEnum) assert str(one) == "ONE" assert int(one) == 1 assert one == 1 assert TestEnum.enums() == TestEnum.enums() assert TestEnum.enums() == [0, 1, 2] segyio-1.8.3/python/test/segy.py0000664000372000037200000015211213407674361016262 0ustar travistravis# -*- coding: utf-8 -*- from __future__ import absolute_import try: from future_builtins import zip, map except ImportError: pass from types import GeneratorType import itertools import filecmp import shutil import numpy as np import numpy.testing as npt import pytest from pytest import approx from . import tmpfiles, small, smallps import segyio from segyio import TraceField, BinField, TraceSortingFormat from segyio.field import Field from segyio.line import Line, HeaderLine from segyio.trace import Trace, Header small_sus = [ (segyio.su.open, { 'filename': 'test-data/small.su', 'iline': 5, 'xline': 21 }), (segyio.su.open, { 'filename': 'test-data/small-lsb.su', 'iline': 5, 'xline': 21, 'endian': 'lsb' }), ] small_segys = [ (segyio.open, { 'filename': 'test-data/small.sgy' }), (segyio.open, { 'filename': 'test-data/small-lsb.sgy', 'endian': 'little' }), ] smallfiles = small_segys + small_sus @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_inline_4(openfn, kwargs): with openfn(**kwargs) as f: sample_count = len(f.samples) assert 50 == sample_count data = f.iline[4] assert 4.2 == approx(data[0, 0], abs=1e-6) # middle sample assert 4.20024 == approx(data[0, sample_count // 2 - 1], abs=1e-6) # last sample assert 4.20049 == approx(data[0, -1], abs=1e-6) # middle xline middle_line = 2 # first sample assert 4.22 == approx(data[middle_line, 0], abs=1e-5) # middle sample assert 4.22024 == approx(data[middle_line, sample_count // 2 - 1], abs=1e-6) # last sample assert 4.22049 == approx(data[middle_line, -1], abs=1e-6) # last xline last_line = (len(f.xlines) - 1) # first sample assert 4.24 == approx(data[last_line, 0], abs=1e-5) # middle sample assert 4.24024 == approx(data[last_line, sample_count // 2 - 1], abs=1e-6) # last sample assert 4.24049 == approx(data[last_line, sample_count - 1], abs=1e-6) def test_inline_4_seismic_unix(): with segyio.su.open('test-data/small.su', iline = 5, xline = 21, endian = 'big', ) as f: sample_count = len(f.samples) assert 50 == sample_count data = f.iline[4] assert 4.2 == approx(data[0, 0], abs=1e-6) # middle sample assert 4.20024 == approx(data[0, sample_count // 2 - 1], abs=1e-6) # last sample assert 4.20049 == approx(data[0, -1], abs=1e-6) # middle xline middle_line = 2 # first sample assert 4.22 == approx(data[middle_line, 0], abs=1e-5) # middle sample assert 4.22024 == approx(data[middle_line, sample_count // 2 - 1], abs=1e-6) # last sample assert 4.22049 == approx(data[middle_line, -1], abs=1e-6) # last xline last_line = (len(f.xlines) - 1) # first sample assert 4.24 == approx(data[last_line, 0], abs=1e-5) # middle sample assert 4.24024 == approx(data[last_line, sample_count // 2 - 1], abs=1e-6) # last sample assert 4.24049 == approx(data[last_line, sample_count - 1], abs=1e-6) @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_xline_22(openfn, kwargs): with openfn(**kwargs) as f: data = f.xline[22] size = len(f.samples) # first iline # first sample assert 1.22 == approx(data[0, 0], abs=1e-5) # middle sample assert 1.22024 == approx(data[0, size // 2 - 1], abs=1e-6) # last sample assert 1.22049 == approx(data[0, size - 1], abs=1e-6) # middle iline middle_line = 2 # first sample assert 3.22 == approx(data[middle_line, 0], abs=1e-5) # middle sample assert 3.22024 == approx(data[middle_line, size // 2 - 1], abs=1e-6) # last sample assert 3.22049 == approx(data[middle_line, size - 1], abs=1e-6) # last iline last_line = len(f.ilines) - 1 # first sample assert 5.22 == approx(data[last_line, 0], abs=1e-5) # middle sample assert 5.22024 == approx(data[last_line, size // 2 - 1], abs=1e-6) # last sample assert 5.22049 == approx(data[last_line, size - 1], abs=1e-6) @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_iline_slicing(openfn, kwargs): with openfn(**kwargs) as f: assert len(f.ilines) == sum(1 for _ in f.iline) assert len(f.ilines) == sum(1 for _ in f.iline[1:6]) assert len(f.ilines) == sum(1 for _ in f.iline[5:0:-1]) assert len(f.ilines) // 2 == sum(1 for _ in f.iline[0::2]) assert len(f.ilines) == sum(1 for _ in f.iline[1:]) assert 3 == sum(1 for _ in f.iline[::2]) assert 0 == sum(1 for _ in f.iline[12:24]) assert 3 == sum(1 for _ in f.iline[:4]) assert 2 == sum(1 for _ in f.iline[2:6:2]) @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_xline_slicing(openfn, kwargs): with openfn(**kwargs) as f: assert len(f.xlines) == sum(1 for _ in f.xline) assert len(f.xlines) == sum(1 for _ in f.xline[20:25]) assert len(f.xlines) == sum(1 for _ in f.xline[25:19:-1]) assert 3 == sum(1 for _ in f.xline[0::2]) assert 3 == sum(1 for _ in f.xline[::2]) assert len(f.xlines) == sum(1 for _ in f.xline[20:]) assert 0 == sum(1 for _ in f.xline[12:18]) assert 5 == sum(1 for _ in f.xline[:25]) assert 2 == sum(1 for _ in f.xline[:25:3]) @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_open_transposed_lines(openfn, kwargs): with openfn(**kwargs) as f: il = f.ilines xl = f.xlines with segyio.open("test-data/small.sgy", "r", segyio.TraceField.CROSSLINE_3D, segyio.TraceField.INLINE_3D) as f: assert list(il) == list(f.xlines) assert list(xl) == list(f.ilines) # only run this test for the SEG-Ys, because the SU files are in IEEE float, # not IBM float @pytest.mark.parametrize(('openfn', 'kwargs'), small_segys) def test_file_info(openfn, kwargs): with openfn(**kwargs) as f: assert 2 == f.sorting assert 1 == f.offsets assert 1 == int(f.format) assert np.single == f.dtype xlines = list(range(20, 25)) ilines = list(range(1, 6)) assert xlines == list(f.xlines) assert ilines == list(f.ilines) assert 25 == f.tracecount assert len(f.trace) == f.tracecount assert 50 == len(f.samples) def test_open_nostrict(): with segyio.open("test-data/small.sgy", strict=False): pass def test_open_ignore_geometry(): with segyio.open("test-data/small.sgy", ignore_geometry=True) as f: with pytest.raises(ValueError): _ = f.iline[0] @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_traces_slicing(openfn, kwargs): with openfn(**kwargs) as f: traces = list(map(np.copy, f.trace[0:6:2])) assert len(traces) == 3 assert traces[0][49] == f.trace[0][49] assert traces[1][49] == f.trace[2][49] assert traces[2][49] == f.trace[4][49] rev_traces = list(map(np.copy, f.trace[4::-2])) assert rev_traces[0][49] == f.trace[4][49] assert rev_traces[1][49] == f.trace[2][49] assert rev_traces[2][49] == f.trace[0][49] # make sure buffers can be reused for i, trace in enumerate(f.trace[0:6:2]): assert np.array_equal(trace, traces[i]) def test_traces_offset(): with segyio.open("test-data/small-ps.sgy") as f: assert 2 == len(f.offsets) assert [1, 2] == list(f.offsets) # traces are laid out |l1o1 l1o2 l2o1 l2o2...| # where l = iline number and o = offset number # traces are not re-indexed according to offsets # see make-ps-file.py for value formula assert 101.01 == approx(f.trace[0][0], abs=1e-4) assert 201.01 == approx(f.trace[1][0], abs=1e-4) assert 101.02 == approx(f.trace[2][0], abs=1e-4) assert 201.02 == approx(f.trace[3][0], abs=1e-4) assert 102.01 == approx(f.trace[6][0], abs=1e-4) def test_headers_offset(): with segyio.open("test-data/small-ps.sgy") as f: il, xl = TraceField.INLINE_3D, TraceField.CROSSLINE_3D assert f.header[0][il] == f.header[1][il] assert f.header[1][il] == f.header[2][il] assert f.header[0][xl] == f.header[1][xl] assert not f.header[1][xl] == f.header[2][xl] @pytest.mark.parametrize(('openfn', 'kwargs'), small_sus) def test_disabled_methods_seismic_unix(openfn, kwargs): with openfn(**kwargs) as f: with pytest.raises(NotImplementedError): _ = f.text[0] with pytest.raises(NotImplementedError): _ = f.bin with pytest.raises(NotImplementedError): f.bin = {} @pytest.mark.parametrize(('openfn', 'kwargs'), small_segys) def test_header_dict_methods(openfn, kwargs): with openfn(**kwargs) as f: assert 89 == len(list(f.header[0].keys())) assert 89 == len(list(f.header[1].values())) assert 89 == len(list(f.header[2].items())) assert 89 == len(list(f.header[3])) assert 0 not in f.header[0] assert 1 in f.header[0] assert segyio.su.cdpx in f.header[0] iter(f.header[0]) assert 30 == len(f.bin.keys()) assert 30 == len(list(f.bin.values())) assert 30 == len(list(f.bin.items())) assert 30 == len(f.bin) iter(f.bin) def test_header_dropped_writes(small): with segyio.open(small, mode='r+') as f: f.header[10] = { 1: 5, 5: 10 } with segyio.open(small, mode='r+') as f: x, y = f.header[10], f.header[10] assert x[1, 5] == { 1: 5, 5: 10 } assert y[1, 5] == { 1: 5, 5: 10 } # write to x[1] is invisible to y x[1] = 6 assert x[1] == 6 assert y[1] == 5 y.reload() assert x[1] == 6 assert y[1] == 6 x[1] = 5 assert x[1] == 5 assert y[1] == 6 # the write to x[1] is lost y[5] = 1 assert x[1] == 5 assert x.reload() assert x[1] == 6 assert y[1, 5] == { 1: 6, 5: 1 } def test_headers_line_offset(smallps): il, xl = TraceField.INLINE_3D, TraceField.CROSSLINE_3D with segyio.open(smallps, "r+") as f: f.header.iline[1, 2] = {il: 11} f.header.iline[1, 2] = {xl: 13} with segyio.open(smallps, strict=False) as f: assert f.header[0][il] == 1 assert f.header[1][il] == 11 assert f.header[2][il] == 1 assert f.header[0][xl] == 1 assert f.header[1][xl] == 13 assert f.header[2][xl] == 2 @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_attributes(openfn, kwargs): with openfn(**kwargs) as f: il = kwargs.get('iline', TraceField.INLINE_3D) xl = kwargs.get('xline', TraceField.CROSSLINE_3D) assert 1 == f.attributes(il)[0] assert 20 == f.attributes(xl)[0] assert f.tracecount == len(f.attributes(il)) assert iter(f.attributes(il)) ils = [(i // 5) + 1 for i in range(25)] attrils = list(map(int, f.attributes(il)[:])) assert ils == attrils xls = [(i % 5) + 20 for i in range(25)] attrxls = list(map(int, f.attributes(xl)[:])) assert xls == attrxls ils = [(i // 5) + 1 for i in range(25)][::-1] attrils = list(map(int, f.attributes(il)[::-1])) assert ils == attrils xls = [(i % 5) + 20 for i in range(25)][::-1] attrxls = list(map(int, f.attributes(xl)[::-1])) assert xls == attrxls assert f.header[0][il] == f.attributes(il)[0] f.mmap() assert f.header[0][il] == f.attributes(il)[0] ils = [(i // 5) + 1 for i in range(25)][1:21:3] attrils = list(map(int, f.attributes(il)[1:21:3])) assert ils == attrils xls = [(i % 5) + 20 for i in range(25)][2:17:5] attrxls = list(map(int, f.attributes(xl)[2:17:5])) assert xls == attrxls ils = [1, 2, 3, 4, 5] attrils = list(map(int, f.attributes(il)[[0, 5, 11, 17, 23]])) assert ils == attrils ils = [1, 2, 3, 4, 5] indices = np.asarray([0, 5, 11, 17, 23]) attrils = list(map(int, f.attributes(il)[indices])) assert ils == attrils def test_iline_offset(): with segyio.open("test-data/small-ps.sgy") as f: line1 = f.iline[1, 1] assert 101.01 == approx(line1[0][0], abs=1e-4) assert 101.02 == approx(line1[1][0], abs=1e-4) assert 101.03 == approx(line1[2][0], abs=1e-4) assert 101.01001 == approx(line1[0][1], abs=1e-4) assert 101.01002 == approx(line1[0][2], abs=1e-4) assert 101.02001 == approx(line1[1][1], abs=1e-4) line2 = f.iline[1, 2] assert 201.01 == approx(line2[0][0], abs=1e-4) assert 201.02 == approx(line2[1][0], abs=1e-4) assert 201.03 == approx(line2[2][0], abs=1e-4) assert 201.01001 == approx(line2[0][1], abs=1e-4) assert 201.01002 == approx(line2[0][2], abs=1e-4) assert 201.02001 == approx(line2[1][1], abs=1e-4) with pytest.raises(KeyError): _ = f.iline[1, 0] with pytest.raises(KeyError): _ = f.iline[1, 3] with pytest.raises(KeyError): _ = f.iline[100, 1] with pytest.raises(TypeError): _ = f.iline[1, {}] def test_iline_slice_fixed_offset(): with segyio.open("test-data/small-ps.sgy") as f: for i, ln in enumerate(f.iline[:, 1], 1): assert i + 100.01 == approx(ln[0][0], abs=1e-4) assert i + 100.02 == approx(ln[1][0], abs=1e-4) assert i + 100.03 == approx(ln[2][0], abs=1e-4) assert i + 100.01001 == approx(ln[0][1], abs=1e-4) assert i + 100.01002 == approx(ln[0][2], abs=1e-4) assert i + 100.02001 == approx(ln[1][1], abs=1e-4) def test_iline_slice_fixed_line(): with segyio.open("test-data/small-ps.sgy") as f: for i, ln in enumerate(f.iline[1, :], 1): off = i * 100 assert off + 1.01 == approx(ln[0][0], abs=1e-4) assert off + 1.02 == approx(ln[1][0], abs=1e-4) assert off + 1.03 == approx(ln[2][0], abs=1e-4) assert off + 1.01001 == approx(ln[0][1], abs=1e-4) assert off + 1.01002 == approx(ln[0][2], abs=1e-4) assert off + 1.02001 == approx(ln[1][1], abs=1e-4) def test_iline_slice_all_offsets(): with segyio.open("test-data/small-ps.sgy") as f: offs, ils = len(f.offsets), len(f.ilines) assert offs * ils == sum(1 for _ in f.iline[:, :]) assert offs * ils == sum(1 for _ in f.iline[:, ::-1]) assert offs * ils == sum(1 for _ in f.iline[::-1, :]) assert offs * ils == sum(1 for _ in f.iline[::-1, ::-1]) assert 0 == sum(1 for _ in f.iline[:, 10:12]) assert 0 == sum(1 for _ in f.iline[10:12, :]) assert (offs // 2) * ils == sum(1 for _ in f.iline[::2, :]) assert offs * (ils // 2) == sum(1 for _ in f.iline[:, ::2]) assert (offs // 2) * ils == sum(1 for _ in f.iline[::-2, :]) assert offs * (ils // 2) == sum(1 for _ in f.iline[:, ::-2]) assert (offs // 2) * (ils // 2) == sum(1 for _ in f.iline[::2, ::2]) assert (offs // 2) * (ils // 2) == sum(1 for _ in f.iline[::2, ::-2]) assert (offs // 2) * (ils // 2) == sum(1 for _ in f.iline[::-2, ::2]) def test_gather_mode(): with segyio.open("test-data/small-ps.sgy") as f: empty = np.empty(0, dtype=np.single) # should raise with pytest.raises(KeyError): assert np.array_equal(empty, f.gather[2, 3, 3]) with pytest.raises(KeyError): assert np.array_equal(empty, f.gather[2, 5, 1]) with pytest.raises(KeyError): assert np.array_equal(empty, f.gather[5, 2, 1]) assert np.array_equal(f.trace[10], f.gather[2, 3, 1]) assert np.array_equal(f.trace[11], f.gather[2, 3, 2]) traces = segyio.tools.collect(f.trace[10:12]) gather = f.gather[2, 3, :] assert np.array_equal(traces, gather) assert np.array_equal(traces, f.gather[2, 3]) assert np.array_equal(empty, f.gather[2, 3, 1:0]) assert np.array_equal(empty, f.gather[2, 3, 3:4]) for g, line in zip(f.gather[1:3, 3, 1], f.iline[1:3]): assert 10 == len(g) assert (10,) == g.shape assert np.array_equal(line[2], g) for g, line in zip(f.gather[1:3, 3, :], f.iline[1:3]): assert 2 == len(g) assert (2, 10) == g.shape assert np.array_equal(line[2], g[0]) for g, line in zip(f.gather[1, 1:3, 1], f.xline[1:3]): assert 10 == len(g) assert (10,) == g.shape assert np.array_equal(line[0], g) for g, line in zip(f.gather[1, 1:3, :], f.xline[1:3]): assert 2 == len(g) assert (2, 10) == g.shape assert np.array_equal(line[0], g[0]) for g, line in zip(f.gather[1, 1:3, 3:4], f.xline[1:3]): assert np.array_equal(empty, g) def test_line_generators(): with segyio.open("test-data/small.sgy") as f: for _ in f.iline: pass for _ in f.xline: pass @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_fast_slow_dimensions(openfn, kwargs): with openfn(**kwargs) as f: for iline, fline in zip(f.iline, f.fast): assert np.array_equal(iline, fline) for xline, sline in zip(f.xline, f.slow): assert np.array_equal(xline, sline) @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_traces_raw(openfn, kwargs): with openfn(**kwargs) as f: gen_traces = np.array(list(map(np.copy, f.trace)), dtype=np.single) raw_traces = f.trace.raw[:] assert np.array_equal(gen_traces, raw_traces) assert len(gen_traces) == f.tracecount assert len(raw_traces) == f.tracecount assert gen_traces[0][49] == raw_traces[0][49] assert gen_traces[1][49] == f.trace.raw[1][49] assert gen_traces[2][49] == raw_traces[2][49] assert np.array_equal(f.trace[10], f.trace.raw[10]) for raw, gen in zip(f.trace.raw[::2], f.trace[::2]): assert np.array_equal(raw, gen) for raw, gen in zip(f.trace.raw[::-1], f.trace[::-1]): assert np.array_equal(raw, gen) def test_read_text_sequence(): with segyio.open('test-data/multi-text.sgy', ignore_geometry = True) as f: for text in f.text[:]: assert text assert iter(f.text) with pytest.deprecated_call(): str(f.text) @tmpfiles('test-data/multi-text.sgy') def test_put_text_sequence(tmpdir): lines = { 1: 'first line', 10: 'last line' } ref = segyio.tools.create_text_header(lines) fname = str(tmpdir / 'multi-text.sgy') with segyio.open(fname, mode = 'r+', ignore_geometry = True) as f, \ segyio.open("test-data/small.sgy") as g: f.text[0] = ref f.text[1] = f.text f.text[-1] = ref f.text[2:4] = [g.text, f.text] assert f.text[2] == g.text[0] f.text[2:3] = [ref] # ref doesn't have to be bytes for reading, but has to in order to compare # with the returned object from text ref = bytearray(ref, 'ascii') ref = bytes(ref) with segyio.open(fname, ignore_geometry = True) as f: for text in f.text: assert text == ref @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_header_getitem_intlikes(openfn, kwargs): with openfn(**kwargs) as f: h = f.header[0] assert 1 == h[37] assert 1 == h[segyio.su.offset] assert 1 == h[TraceField.offset] @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_read_header(openfn, kwargs): with openfn(**kwargs) as f: il = kwargs.get('iline', TraceField.INLINE_3D) assert 1 == f.header[0][il] assert 5 == f.header[-1][il] assert dict(f.header[-1]) == dict(f.header[24]) with pytest.raises(IndexError): _ = f.header[30] with pytest.raises(IndexError): _ = f.header[-30] with pytest.raises(KeyError): _ = f.header[0][188] # between byte offsets with pytest.raises(KeyError): _ = f.header[0][-1] with pytest.raises(KeyError): _ = f.header[0][700] def test_read_header_seismic_unix(): il = 5 with segyio.su.open('test-data/small.su', ignore_geometry = True, endian = 'big') as f: assert 1 == f.header[0][il] assert 1 == f.header[1][il] assert 5 == f.header[-1][il] assert 5 == f.header[24][il] assert dict(f.header[-1]) == dict(f.header[24]) def test_write_header(small): with segyio.open(small, "r+") as f: # assign to a field in a header, write immediately f.header[0][189] = 42 f.flush() assert 42 == f.header[0][189] assert 1 == f.header[1][189] # accessing non-existing offsets raises exceptions with pytest.raises(KeyError): f.header[0][188] = 1 # between byte offsets with pytest.raises(KeyError): f.header[0][-1] = 1 with pytest.raises(KeyError): f.header[0][700] = 1 d = {TraceField.INLINE_3D: 43, TraceField.CROSSLINE_3D: 11, TraceField.offset: 15} # assign multiple fields at once by using a dict f.header[1] = d f.flush() assert 43 == f.header[1][TraceField.INLINE_3D] assert 11 == f.header[1][segyio.su.xline] assert 15 == f.header[1][segyio.su.offset] # looking up multiple values at once returns a { TraceField: value } dict assert d == f.header[1][TraceField.INLINE_3D, TraceField.CROSSLINE_3D, TraceField.offset] # slice-support over headers (similar to trace) for _ in f.header[0:10]: pass assert 6 == len(list(f.header[10::-2])) assert 5 == len(list(f.header[10:5:-1])) assert 0 == len(list(f.header[10:5])) d = {TraceField.INLINE_3D: 45, TraceField.CROSSLINE_3D: 10, TraceField.offset: 16} # assign multiple values using alternative syntax f.header[5].update(d) f.flush() assert 45 == f.header[5][TraceField.INLINE_3D] assert 10 == f.header[5][segyio.su.xline] assert 16 == f.header[5][segyio.su.offset] # accept anything with a key-value structure f.header[5].update([(segyio.su.ns, 12), (segyio.su.dt, 4)]) f.header[5].update(((segyio.su.muts, 3), (segyio.su.mute, 7))) f.header[5].update([(segyio.su.muts, 3)], sx=7) f.header[5].update(sy=8) with pytest.raises(TypeError): f.header[0].update(10) with pytest.raises(TypeError): f.header[0].update(None) with pytest.raises(ValueError): f.header[0].update('foo') f.flush() assert 12 == f.header[5][segyio.su.ns] assert 4 == f.header[5][segyio.su.dt] assert 3 == f.header[5][segyio.su.muts] assert 7 == f.header[5][segyio.su.mute] assert 7 == f.header[5][segyio.su.sx] assert 8 == f.header[5][segyio.su.sy] # for-each support for _ in f.header: pass # copy a header f.header[2] = f.header[1] f.flush() d = {TraceField.INLINE_3D: 12, TraceField.CROSSLINE_3D: 13, TraceField.offset: 14} # assign multiple values with a slice f.header[:5] = d f.flush() for i in range(5): assert 12 == f.header[i][TraceField.INLINE_3D] assert 13 == f.header[i][segyio.su.xline] assert 14 == f.header[i][segyio.su.offset] # don't use this interface in production code, it's only for testing # i.e. don't access buf of treat it as a list # assertEqual(list(f.header[2].buf), list(f.header[1].buf)) def test_write_binary(small): with segyio.open(small, "r+") as f: f.bin[3213] = 5 f.flush() assert 5 == f.bin[3213] # accessing non-existing offsets raises exceptions with pytest.raises(KeyError): _ = f.bin[0] with pytest.raises(KeyError): _ = f.bin[50000] with pytest.raises(KeyError): _ = f.bin[3214] d = {BinField.Traces: 43, BinField.SweepFrequencyStart: 11} # assign multiple fields at once by using a dict f.bin = d f.flush() assert 43 == f.bin[segyio.su.ntrpr] assert 11 == f.bin[segyio.su.hsfs] d = {BinField.Traces: 45, BinField.SweepFrequencyStart: 10} # assign multiple values using alternative syntax f.bin.update(d) f.flush() assert 45 == f.bin[segyio.su.ntrpr] assert 10 == f.bin[segyio.su.hsfs] # accept anything with a key-value structure f.bin.update([(segyio.su.jobid, 12), (segyio.su.lino, 4)]) f.bin.update(((segyio.su.reno, 3), (segyio.su.hdt, 7))) f.flush() assert 12 == f.bin[segyio.su.jobid] assert 4 == f.bin[segyio.su.lino] assert 3 == f.bin[segyio.su.reno] assert 7 == f.bin[segyio.su.hdt] # looking up multiple values at once returns a { TraceField: value } dict assert d == f.bin[BinField.Traces, BinField.SweepFrequencyStart] # copy a header f.bin = f.bin def test_write_header_update_atomic(small): with segyio.open(small, "r+") as f: orig = dict(f.header[10]) d = { 1: 10, 37: 4, 73: 15, 2: 10, # this key raises error } # use the same instance all the time, to also catch the case where # update dirties the backing storage header = f.header[10] with pytest.raises(KeyError): header.update(d) assert orig == header # flushing the header should just write a clean buffer header.flush() assert orig == header del d[2] header.update(d) assert header[1] == 10 assert header[73] == 15 assert f.header[10][37] == 4 fresh = orig.copy() fresh.update(d) assert orig != header assert orig != f.header[10] assert fresh == f.header[10] assert header == f.header[10] def test_fopen_error(): # non-existent file with pytest.raises(IOError): segyio.open("no_dir/no_file") # non-existant mode with pytest.raises(ValueError): segyio.open("test-data/small.sgy", "foo") with pytest.raises(ValueError): segyio.open("test-data/small.sgy", "r+b+toolong") def test_wrong_lineno(): with pytest.raises(KeyError): with segyio.open("test-data/small.sgy") as f: _ = f.iline[3000] with pytest.raises(KeyError): with segyio.open("test-data/small.sgy") as f: _ = f.xline[2] def test_open_wrong_inline(): with pytest.raises(IndexError): with segyio.open("test-data/small.sgy", "r", 2): pass with segyio.open("test-data/small.sgy", "r", 2, strict=False): pass def test_open_wrong_crossline(): with pytest.raises(IndexError): with segyio.open("test-data/small.sgy", "r", 189, 2): pass with segyio.open("test-data/small.sgy", "r", 189, 2, strict=False): pass def test_wonky_dimensions(): with segyio.open("test-data/Mx1.sgy"): pass with segyio.open("test-data/1xN.sgy"): pass with segyio.open("test-data/1x1.sgy"): pass def test_open_fails_unstructured(): with segyio.open("test-data/small.sgy", "r", 37, strict=False) as f: with pytest.raises(ValueError): _ = f.iline[10] with pytest.raises(ValueError): _ = f.iline[:, :] with pytest.raises(ValueError): _ = f.xline[:, :] # operations that don't rely on geometry still works assert f.header[2][189] == 1 assert (list(f.attributes(189)[:]) == [(i // 5) + 1 for i in range(len(f.trace))]) def test_write_with_narrowing(small): with segyio.open(small, mode = 'r+') as f: with pytest.warns(RuntimeWarning): ones = np.ones(len(f.samples), dtype=np.float64) f.trace[0] = ones assert np.array_equal(f.trace[0], ones) with pytest.warns(RuntimeWarning): twos = [np.single(2.0) for _ in range(len(f.samples))] f.trace[1] = twos assert np.array_equal(f.trace[1], twos) with pytest.warns(RuntimeWarning): first = f.ilines[0] shape = f.iline[first].shape ones = np.ones(shape, dtype=np.float64) f.iline[first] = ones assert np.array_equal(f.iline[first], ones) with pytest.warns(RuntimeWarning): last = f.xlines[-1] shape = f.xline[last].shape threes = np.ones(shape, dtype=np.float64) * 3 f.xline[last] = threes assert np.array_equal(f.xline[last], threes) def test_write_with_array_likes(small): with segyio.open(small, mode = 'r+') as f: with pytest.warns(RuntimeWarning): ones = np.ones(3 * len(f.samples), dtype='single') # ::3 makes the array non-contiguous f.trace[0] = ones[::3] assert np.array_equal(f.trace[0], ones[::3]) with pytest.warns(RuntimeWarning): ones = np.ones(len(f.samples), dtype='single') f.trace[0] = (1 for _ in range(len(f.samples))) assert np.array_equal(f.trace[0], ones) def test_assign_all_traces(small): orig = str(small.dirname + '/small.sgy') copy = str(small.dirname + '/copy.sgy') shutil.copy(orig, copy) with segyio.open(orig) as f: traces = f.trace.raw[:] * 2.0 with segyio.open(copy, 'r+') as f: f.trace[:] = traces[:] with segyio.open(copy) as f: assert np.array_equal(f.trace.raw[:], traces) def test_traceaccess_from_array(): a = np.arange(10, dtype=np.int) b = np.arange(10, dtype=np.int32) c = np.arange(10, dtype=np.int64) d = np.arange(10, dtype=np.intc) with segyio.open("test-data/small.sgy") as f: _ = f.trace[a[0]] _ = f.trace[b[1]] _ = f.trace[c[2]] _ = f.trace[d[3]] def test_create_sgy(small): orig = str(small.dirname + '/small.sgy') fresh = str(small.dirname + '/fresh.sgy') with segyio.open(orig) as src: spec = segyio.spec() spec.format = int(src.format) spec.sorting = int(src.sorting) spec.samples = src.samples spec.ilines = src.ilines spec.xlines = src.xlines with segyio.create(fresh, spec) as dst: dst.text[0] = src.text[0] dst.bin = src.bin # copy all headers dst.header = src.header for i, srctr in enumerate(src.trace): dst.trace[i] = srctr dst.trace = src.trace # this doesn't work yet, some restructuring is necessary # if it turns out to be a desired feature it's rather easy to do # for dsth, srch in zip(dst.header, src.header): # dsth = srch # for dsttr, srctr in zip(dst.trace, src.trace): # dsttr = srctr assert filecmp.cmp(orig, fresh) def test_ref_getitem(small): with segyio.open(small, mode = 'r+') as f: with f.trace.ref as ref: expected = ref[10].copy() x = ref[10] y = ref[10] x[5] = 0 # getting a new trace within the same with block should not # invalidate other refs y = ref[11] x[6] = 1.6721 x[5] = 52 y[0] = 0 assert ref[10][5] == 52 assert ref[10][6] == approx(1.6721) assert len(ref.refs) == 2 z = ref[12] z[0] = 0 assert len(ref.refs) == 3 x, y = None, None ref.flush() assert len(ref.refs) == 1 with segyio.open(small) as f: expected[5] = 52 expected[6] = 1.6721 npt.assert_array_almost_equal(expected, f.trace[10]) def test_ref_inplace_add_foreach(small): with segyio.open(small, mode = 'r+') as f: expected = f.trace.raw[:] + 1.617 with f.trace.ref as ref: for x in ref[:]: x += 1.617 with segyio.open(small) as f: npt.assert_array_almost_equal(expected, f.trace.raw[:]) def test_ref_preserve_change_except_block(small): with segyio.open(small, mode = 'r+') as f: expected = f.trace.raw[:] expected[10][0] = 0 with f.trace.ref as ref: try: for i, x in enumerate(ref[:]): if i == 10: raise RuntimeError except RuntimeError: x[0] = 0 with segyio.open(small) as f: result = f.trace.raw[:] npt.assert_array_almost_equal(expected[10], result[10]) npt.assert_array_almost_equal(expected, result) def test_ref_post_loop_var(small): with segyio.open(small, mode = 'r+') as f: expected = f.trace[-1] expected[0] = 1.617 with f.trace.ref as ref: for x in ref[:]: pass x[0] = 1.617 with segyio.open(small) as f: npt.assert_array_almost_equal(expected, f.trace[-1]) def test_ref_sliced(small): with segyio.open(small, mode = 'r+') as f: expected = f.trace.raw[:] expected[10:15] += expected[:5] with f.trace.ref as ref: for x, y in zip(ref[10:15], f.trace[:]): np.copyto(x, x + y) with segyio.open(small) as f: npt.assert_array_almost_equal(expected, f.trace.raw[:]) def test_ref_mixed_for_else(small): with segyio.open(small, mode = 'r+') as f: samples = len(f.samples) zeros = np.zeros(samples, dtype = f.dtype) ones = np.ones(samples, dtype = f.dtype) expected = f.trace.raw[:] expected[7] = zeros expected[5:10] += 1.617 expected[9] = ones with f.trace.ref as ref: ref[7] = zeros for x in ref[5:10]: # break won't run, so enter else block if len(x) == 0: break x += 1.617 else: # else should preserve last x np.copyto(x, ones) with segyio.open(small) as f: npt.assert_array_almost_equal(expected, f.trace.raw[:]) def test_ref_new_file(small): # this is the case the trace.ref feature was designed to support, namely # creating a file trace-by-trace based on some transformation of another # file, or an operation on multiple, where the trace index itself is # uninteresting. orig = str(small.dirname + '/small.sgy') fresh = str(small.dirname + '/fresh.sgy') with segyio.open(orig) as src: spec = segyio.tools.metadata(src) with segyio.create(fresh, spec) as dst: dst.text[0] = src.text[0] dst.bin = src.bin # copy all headers dst.header = src.header with dst.trace.ref as ref: for x, y in zip(ref[:], src.trace): # x default-inits to 0, so += is essentially copyto() # since traces hasn't been written yet, this has to handle # read miss errors x += y with segyio.open(fresh) as dst: npt.assert_array_almost_equal(src.trace.raw[:], dst.trace.raw[:]) def test_create_sgy_truncate(small): orig = str(small.dirname + '/small.sgy') trunc = str(small.dirname + '/text-truncated.sgy') with segyio.open(orig) as src: spec = segyio.tools.metadata(src) # repeat the text header 3 times text = src.text[0] text = text + text + text with segyio.create(trunc, spec) as dst: dst.bin = src.bin dst.text[0] = text dst.header = src.header for i, srctr in enumerate(src.trace): dst.trace[i] = srctr dst.trace = src.trace assert filecmp.cmp(orig, trunc) def test_create_sgy_shorter_traces(small): orig = str(small.dirname + '/small.sgy') fresh = str(small.dirname + '/small_created_shorter.sgy') with segyio.open(orig) as src: spec = segyio.spec() spec.format = int(src.format) spec.sorting = int(src.sorting) spec.samples = src.samples[:20] # reduces samples per trace spec.ilines = src.ilines spec.xlines = src.xlines with segyio.create(fresh, spec) as dst: for i, srch in enumerate(src.header): dst.header[i] = srch d = {TraceField.INLINE_3D: srch[TraceField.INLINE_3D] + 100} dst.header[i] = d for lineno in dst.ilines: dst.iline[lineno] = src.iline[lineno] # alternative form using left-hand-side slices dst.iline[2:4] = src.iline for lineno in dst.xlines: dst.xline[lineno] = src.xline[lineno] with segyio.open(fresh) as dst: assert 20 == len(dst.samples) assert [x + 100 for x in src.ilines] == list(dst.ilines) @pytest.mark.parametrize('endian', ['lsb', 'msb']) def test_create_from_naught(endian, tmpdir): spec = segyio.spec() spec.format = 5 spec.sorting = 1 spec.samples = range(150) spec.ilines = range(1, 11) spec.xlines = range(1, 6) spec.endian = endian with segyio.create(tmpdir / "mk.sgy", spec) as dst: tr = np.arange(start=1.000, stop=1.151, step=0.001, dtype=np.single) for i in range(len(dst.trace)): dst.trace[i] = tr tr += 1.000 for il in spec.ilines: dst.header.iline[il] = {TraceField.INLINE_3D: il} for xl in spec.xlines: dst.header.xline[xl] = {TraceField.CROSSLINE_3D: xl} # Set header field 'offset' to 1 in all headers dst.header = {TraceField.offset: 1} with segyio.open(tmpdir / "mk.sgy", endian = endian) as f: assert 1 == approx(f.trace[0][0], abs=1e-4) assert 1.001 == approx(f.trace[0][1], abs=1e-4) assert 1.149 == approx(f.trace[0][-1], abs=1e-4) assert 50.100 == approx(f.trace[-1][100], abs=1e-4) assert f.header[0][TraceField.offset] == f.header[1][TraceField.offset] assert 1 == f.header[1][TraceField.offset] assert f.sorting == TraceSortingFormat.CROSSLINE_SORTING @pytest.mark.parametrize('endian', ['lsb', 'msb']) def test_create_from_naught_prestack(endian, tmpdir): spec = segyio.spec() spec.format = 5 #spec.sorting not set by test design spec.samples = range(7) spec.ilines = range(1, 4) spec.xlines = range(1, 3) spec.offsets = range(1, 6) spec.endian = endian with segyio.create(tmpdir / "mk-ps.sgy", spec) as dst: arr = np.arange(start=0.000, stop=0.007, step=0.001, dtype=np.single) arr = np.concatenate([[arr + 0.01], [arr + 0.02]], axis=0) lines = [arr + i for i in spec.ilines] cube = [(off * 100) + line for line in lines for off in spec.offsets] dst.iline[:, :] = cube for of in spec.offsets: for il in spec.ilines: dst.header.iline[il, of] = {TraceField.INLINE_3D: il, TraceField.offset: of } for xl in spec.xlines: dst.header.xline[xl, of] = {TraceField.CROSSLINE_3D: xl} with segyio.open(tmpdir / "mk-ps.sgy", endian = endian) as f: assert 101.010 == approx(f.trace[0][0], abs=1e-4) assert 101.011 == approx(f.trace[0][1], abs=1e-4) assert 101.016 == approx(f.trace[0][-1], abs=1e-4) assert 503.025 == approx(f.trace[-1][5], abs=1e-4) assert f.header[0][TraceField.offset] != f.header[1][TraceField.offset] assert 1 == f.header[0][TraceField.offset] assert 2 == f.header[1][TraceField.offset] for x, y in zip(f.iline[:, :], cube): assert list(x.flatten()) == list(y.flatten()) assert f.sorting == TraceSortingFormat.INLINE_SORTING @pytest.mark.parametrize('endian', ['lsb', 'msb']) def test_create_unstructured_hasattrs(endian, tmpdir): spec = segyio.spec() spec.format = 5 spec.samples = range(150) spec.tracecount = 50 spec.endian = endian with segyio.create(tmpdir / "mk.sgy", spec) as dst: # accessing the sorting, inline and crossline attributes should work, # but not raise errors assert not dst.sorting assert not dst.ilines assert not dst.xlines assert dst.unstructured @pytest.mark.parametrize('endian', ['lsb', 'msb']) def test_create_from_naught_unstructured(endian, tmpdir): spec = segyio.spec() spec.format = 5 spec.samples = range(150) spec.tracecount = 50 spec.endian = endian with segyio.create(tmpdir / "unstructured.sgy", spec) as dst: tr = np.array(range(150), dtype = np.single) for i in range(len(dst.trace)): dst.trace[i] = tr tr += 1 # Set header field 'offset' to 1 in all headers dst.header = {TraceField.offset: 1} with segyio.open(tmpdir / "unstructured.sgy", ignore_geometry=True, endian=endian) as f: assert 1 == approx(f.trace[1][0], abs=1e-4) assert 2 == approx(f.trace[1][1], abs=1e-4) assert 150 == approx(f.trace[1][-1], abs=1e-4) assert 149 == approx(f.trace[-1][100], abs=1e-4) assert f.header[10][TraceField.offset] == f.header[25][TraceField.offset] assert 1 == f.header[1][TraceField.offset] def test_create_write_lines(tmpdir): mklines(tmpdir / "mklines.sgy") with segyio.open(tmpdir / "mklines.sgy") as f: assert 1 == approx(f.iline[1][0][0], abs=1e-4) assert 2.004 == approx(f.iline[2][0][4], abs=1e-4) assert 2.014 == approx(f.iline[2][1][4], abs=1e-4) assert 8.043 == approx(f.iline[8][4][3], abs=1e-4) def test_create_sgy_skip_lines(tmpdir): mklines(tmpdir / "lines.sgy") with segyio.open(tmpdir / "lines.sgy") as src: spec = segyio.spec() spec.format = int(src.format) spec.sorting = int(src.sorting) spec.samples = src.samples spec.ilines = src.ilines[::2] spec.xlines = src.xlines[::2] with segyio.create(tmpdir / "lines-halved.sgy", spec) as dst: # use the inline headers as base dst.header.iline = src.header.iline[::2] # then update crossline numbers from the crossline headers for xl in dst.xlines: f = next(src.header.xline[xl])[TraceField.CROSSLINE_3D] dst.header.xline[xl] = {TraceField.CROSSLINE_3D: f} # but we override the last xline to be 6, not 5 dst.header.xline[5] = {TraceField.CROSSLINE_3D: 6} dst.iline = src.iline[::2] with segyio.open(tmpdir / "lines-halved.sgy") as f: assert list(f.ilines) == list(spec.ilines) assert list(f.xlines) == [1, 3, 6] assert 1 == approx(f.iline[1][0][0], abs=1e-4) assert 3.004 == approx(f.iline[3][0][4], abs=1e-4) assert 3.014 == approx(f.iline[3][1][4], abs=1e-4) assert 7.023 == approx(f.iline[7][2][3], abs=1e-4) def mklines(fname): spec = segyio.spec() spec.format = 5 spec.sorting = 2 spec.samples = range(10) spec.ilines = range(1, 11) spec.xlines = range(1, 6) # create a file with 10 inlines, with values on the form l.0tv where # l = line no # t = trace number (within line) # v = trace value # i.e. 2.043 is the value at inline 2's fourth trace's third value with segyio.create(fname, spec) as dst: ln = np.arange(start=0, stop=0.001 * (5 * 10), step=0.001, dtype=np.single).reshape(5, 10) for il in spec.ilines: ln += 1 dst.header.iline[il] = {TraceField.INLINE_3D: il} dst.iline[il] = ln for xl in spec.xlines: dst.header.xline[xl] = {TraceField.CROSSLINE_3D: xl} def test_create_bad_specs(tmpdir): class C: pass c = C() mandatory = [('iline', 189), ('xline', 193), ('samples', [10, 11, 12]), ('format', 1), ('t0', 10.2)] for attr, val in mandatory: setattr(c, attr, val) with pytest.raises(AttributeError): with segyio.create(tmpdir / 'foo' + attr, c): pass c.tracecount = 10 with segyio.create(tmpdir / 'tracecount', c): pass del c.tracecount c.ilines = [1, 2, 3] with pytest.raises(AttributeError): with segyio.create(tmpdir / 'ilines', c): pass c.xlines = [4, 6, 8] with pytest.raises(AttributeError): with segyio.create(tmpdir / 'xlines', c): pass c.offsets = [1] with segyio.create(tmpdir / 'ok.sgy', c): pass @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_segyio_types(openfn, kwargs): with openfn(**kwargs) as f: assert isinstance(f.sorting, int) assert isinstance(f.ext_headers, int) assert isinstance(f.tracecount, int) assert isinstance(f.samples, np.ndarray) from segyio.depth import Depth assert isinstance(f.depth_slice, Depth) assert isinstance(f.depth_slice[1], np.ndarray) assert isinstance(f.depth_slice[1:23], GeneratorType) assert isinstance(f.ilines, np.ndarray) assert isinstance(f.iline, Line) assert isinstance(f.iline[1], np.ndarray) assert isinstance(f.iline[1:3], GeneratorType) assert isinstance(f.iline[1][0], np.ndarray) assert isinstance(f.iline[1][0:2], np.ndarray) assert isinstance(float(f.iline[1][0][0]), float) assert isinstance(f.iline[1][0][0:3], np.ndarray) assert isinstance(f.xlines, np.ndarray) assert isinstance(f.xline, Line) assert isinstance(f.xline[21], np.ndarray) assert isinstance(f.xline[21:23], GeneratorType) assert isinstance(f.xline[21][0], np.ndarray) assert isinstance(f.xline[21][0:2], np.ndarray) assert isinstance(float(f.xline[21][0][0]), float) assert isinstance(f.xline[21][0][0:3], np.ndarray) assert isinstance(f.header, Header) assert isinstance(f.header.iline, HeaderLine) assert isinstance(f.header.iline[1], GeneratorType) assert isinstance(next(f.header.iline[1]), Field) assert isinstance(f.header.xline, HeaderLine) assert isinstance(f.header.xline[21], GeneratorType) assert isinstance(next(f.header.xline[21]), Field) assert isinstance(f.trace, Trace) assert isinstance(f.trace[0], np.ndarray) @pytest.mark.parametrize(('openfn', 'kwargs'), small_segys) def test_segyio_segy_only_types(openfn, kwargs): with openfn(**kwargs) as f: assert isinstance(f.bin, Field) assert isinstance(f.text, object) # inner TextHeader instance @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_depth_slice_reading(openfn, kwargs): from itertools import islice with openfn(**kwargs) as f: assert len(f.depth_slice) == len(f.samples) for depth_sample in range(len(f.samples))[::5]: depth_slice = f.depth_slice[depth_sample] assert isinstance(depth_slice, np.ndarray) assert depth_slice.shape == (5, 5) for x, y in itertools.product(f.ilines, f.xlines): i, j = x - f.ilines[0], y - f.xlines[0] assert depth_slice[i][j] == approx(f.iline[x][j][depth_sample], abs=1e-6) itr = iter(enumerate(f.depth_slice)) for index, depth_slice in itr: assert isinstance(depth_slice, np.ndarray) assert depth_slice.shape == (5, 5) for x, y in itertools.product(f.ilines, f.xlines): i, j = x - f.ilines[0], y - f.xlines[0] assert depth_slice[i][j] == approx(f.iline[x][j][index], abs=1e-6) next(islice(itr, 5, 5), None) with pytest.raises(IndexError): _ = f.depth_slice[len(f.samples)] def test_depth_slice_array_shape(): with segyio.open("test-data/1xN.sgy") as f: shape = (len(f.fast), len(f.slow)) assert f.depth_slice.shape == shape @pytest.mark.parametrize(('openfn', 'kwargs'), smallfiles) def test_depth_slice_unstructured(openfn, kwargs): with openfn(ignore_geometry = True, **kwargs) as f: traces = f.trace.raw[:] shape = len(f.trace) assert f.depth_slice.shape == shape np.testing.assert_almost_equal(f.depth_slice[0], traces[:,0]) def test_depth_slice_writing(small): from itertools import islice buf = np.empty(shape=(5, 5), dtype=np.single) def value(x, y): return x + (1.0 // 5) * y for x, y in itertools.product(range(5), range(5)): buf[x][y] = value(x, y) with segyio.open(small, "r+") as f: f.depth_slice[7] = buf * 3.14 # assign to depth 7 assert np.allclose(f.depth_slice[7], buf * 3.14) f.depth_slice = [buf * i for i in range(len(f.depth_slice))] # assign to all depths itr = iter(enumerate(f.depth_slice)) for index, depth_slice in itr: assert np.allclose(depth_slice, buf * index) next(islice(itr, 3, 3), None) @pytest.mark.parametrize('endian', ['little', 'big']) def test_no_16bit_overflow_tracecount(endian, tmpdir): spec = segyio.spec() spec.format = 1 spec.sorting = 2 spec.samples = np.arange(501) spec.ilines = np.arange(345) spec.xlines = np.arange(250) spec.endian = endian # build a file with more than 65k traces, which would cause a 16bit int to # overflow. # see https://github.com/Statoil/segyio/issues/235 ones = np.ones(len(spec.samples), dtype = np.single) with segyio.create(tmpdir / 'foo.sgy', spec) as f: assert f.tracecount > 0 assert f.tracecount > 2**16 - 1 f.trace[-1] = ones f.header[-1] = { segyio.TraceField.INLINE_3D: 10, segyio.TraceField.CROSSLINE_3D: 10, segyio.TraceField.offset: 1, } def test_open_2byte_int_format(): with segyio.open('test-data/f3.sgy') as f: assert int(f.format) == 3 assert len(f.samples) == 75 assert f.tracecount == 414 assert list(f.ilines) == list(range(111, 111 + 23)) assert list(f.xlines) == list(range(875, 875 + 18)) assert f.dtype == np.dtype(np.int16) def test_readtrace_int16(): with segyio.open('test-data/f3.sgy') as f: tr = f.trace[10] assert list(tr[20:45: 5]) == [0, -1170, 5198, -2213, -888] assert list(tr[40:19:-5]) == [-888, -2213, 5198, -1170, 0] assert list(tr[53:50:-1]) == [-2609, -2625, 681] @tmpfiles('test-data/f3.sgy') def test_writetrace_int16(tmpdir): with segyio.open(tmpdir / 'f3.sgy', mode = 'r+') as f: tr = np.asarray(range(len(f.samples)), dtype = np.int16) f.trace[0] = tr f.trace[1] = tr + 1 with segyio.open(tmpdir / 'f3.sgy') as f: # read both with trace and raw-with-slice, since sliced raw allocates # and internal buffer that must match the type assert np.array_equal(f.trace[0], tr) assert np.array_equal(f.trace[1], tr + 1) assert np.array_equal(f.trace.raw[:2], [tr, tr+1]) @tmpfiles('test-data/f3.sgy') def test_write_iline_int16(tmpdir): with segyio.open(tmpdir / 'f3.sgy', mode = 'r+') as f: shape = f.iline[f.ilines[0]].shape il = np.arange(np.prod(shape), dtype = np.int16).reshape(shape) f.iline[f.ilines[0]] = il with segyio.open(tmpdir / 'f3.sgy') as f: assert np.array_equal(f.iline[f.ilines[0]], il) def test_missing_format_ibmfloat_fallback(small): with segyio.open(small, mode = 'r+') as f: f.bin[segyio.su.format] = 0 with pytest.warns(UserWarning): with segyio.open(small) as f: assert int(f.format) == 1 assert f.dtype == np.dtype(np.float32) def test_utf8_filename(): with segyio.open('test-data/小文件.sgy') as f: assert list(f.ilines) == [1, 2, 3, 4, 5] @tmpfiles(u'test-data/小文件.sgy') def test_utf8_filename_pypath(tmpdir): with segyio.open(tmpdir / '小文件.sgy') as f: assert list(f.ilines) == [1, 2, 3, 4, 5] def test_interpret_invalid_args(): with segyio.open("test-data/small.sgy", ignore_geometry=True) as f: with pytest.raises(ValueError): il = [1, 2, 3, 4] xl = [20, 21, 22, 23, 24] f.interpret(il, xl) with pytest.raises(ValueError): il = [1, 2, 3, 4, 5] xl = [20, 21, 22, 23, 24] f.interpret(il, xl, sorting=0) with pytest.raises(ValueError): il = [1, 2, 3, 4, 4] xl = [20, 21, 22, 23, 24] f.interpret(il, xl, sorting=0) segyio-1.8.3/python/test/__init__.py0000664000372000037200000000104413407674361017047 0ustar travistravis# -*- coding: utf-8 -*- import shutil import pytest def tmpfiles(*files): def tmpfiles_decorator(func): def func_wrapper(tmpdir): for f in files: shutil.copy(f, str(tmpdir)) func(tmpdir) return func_wrapper return tmpfiles_decorator @pytest.fixture def small(tmpdir): shutil.copy("test-data/small.sgy", str(tmpdir)) return tmpdir / "small.sgy" @pytest.fixture def smallps(tmpdir): shutil.copy("test-data/small-ps.sgy", str(tmpdir)) return tmpdir / "small-ps.sgy"segyio-1.8.3/test-data/0000775000372000037200000000000013407674361014325 5ustar travistravissegyio-1.8.3/test-data/f3.sgy0000664000372000037200000050230413407674361015365 0ustar travistravis@@Ù@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@㈉@@@@@@@@@@@@Ĥ@Ֆ@⅁@@@@@@@@@@@@㈉@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@zaaKKaaԁaՅֆ“Ö@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@KK@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@KK@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@KK@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@㈉@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@K@+okk^tڹ^tڹok+) %*; Iw  p:O/'a  %1U_8k+bvA+oll^n^nol+b[C| ; "'nl *K|zQH2]EO X( ]n~e"UKB+omm^h^hom+7 T4  1 +) hn=T-} \&[TKC q "4q 6C+ onn^b^bon+ i  w [ nrVV9 *&-aO^YOBY hsx/D+!ooo^\^\oo+!SWT{G?% l~$ml0=xV:  UD *_+` @qC'8OG (QvE+"opp^V^Vop+"-W ! 6! Ik& 4 #olc (`Hg?0=![nYF+#oqq^P^Poq+#Oz`S]I :2: R0|0 PR%"  : qk!^v)g"G+$orr^J^Jor+$]8]4TD} S 0, )cLo KI\cz d M "QH+%oss^D^Dos+%3, < > :_Q # q]  VJ R A er5M BuI+&ott^=^=ot+&p[  Jr  1aiYC:K_4I iBS0WJ+'ouu^7^7ou+''nn YN``[sDI:L*J6 v .!p -((ebzK+(ovv^1^1ov+(\f%M5 u]1 yP('9g6^z p" L+)oww^+ ^+ ow+)^/ | ) O 9 ZQ mW8h vnW NQ%/.M+*oxx^%^%ox+*%Bf~ W ZWmz"o`*`-Uu]X{ N++oyy^^oy++%,{gb. f\ b B,E4 q^1 kEzT~OGNO+,ozz^!^!oz+,SqZY .QPUY6A@T4=r@ sw} +z5 @ i2P+-o{{^(^(o{+-  S V ~~ :iPy"K`$F 6t) /Q+.o||^ /^ /o|+.mL1ca@&?  B 3(SaM|WrOMpU #=rj\a0 e@.pkk^m۳^m۳pk.; _h Nxa `7  Io&67KU5.{C jN3dg^A.pll^gۺ^gۺpl.{<|_: N{ J J nc1R" i4B*U~"',1Y 5B.pmm^a^apm.9}p{ > K{YvG :uu !!C*YY AH C_2O '(C.pnn^[^[pn. e *K1OSD5  i-''G 2 UZX$D?pD.poo^U^Upo.=-`` Y 4 j P RZ@&I?c0YE(N) Y bXL-}ghQE.ppp^O^Opp.H"  {`I NIF4%9m+oB L  00?F.pqq^I^Ipq.  X^OOHobx]&p*B{27 bF G.prr^C^Cpr.g62a | I yK#  Nj,//^ [0Q 2 H.pss^=^=ps.\M9  w" .231V#,:;- 8 U R;wCH3 h I.ptt^6^6pt.#+5zN=jT ZReK[`bY >/zVzkQBJ.puu^0^0pu.^ w~  = m%!&  QK/o]w_;( $0 prXR`xK.pvv^*^*pv.) ? kp Jzl]grP'57ha ] ~U { Hi L.pww^$^$pw.z6g =;& 9*e<Y(Jg1K  hM.pxx^ ^ px.~5T > p4}!MF:)J  oQuf=N.pyy^^py.D j#_ V)  N$u?$G' I*5 PG(6_yl iO.pzz^^pz.LI7e+!A> sih*S` O+@Q};B5p@ ; ]!# ha <P.p{{^ "^ "p{.? H % Y ^"Q8|8{8=/ ,]O@U dQ.p||^)^)p|.zE)\\d Y h j {h&UiB~sH"NO!% v=;2 -@2qkk^fܬ^fܬqk2._T2H )#B?K_ 9bX N' u fLsA2qll^`ܳ^`ܳql2Wzz< G7i#;N$ #`}8C9S;"P K(/P}~i B2qmm^Zܺ^Zܺqm2U9u5. T E } Nu6  NV %}`c<^1BgZC2qnn^T^Tqn2i1. V  | J  JH{n; 6B yW='C, jD2qoo^N^Nqo2_V/AUNy x-a #Wp@D  AsE Yv .ew# )E2qpp^H^Hqp2GrO I*"g  Q(~wG7]|t8 3F2qqq^B^Bqq2'Y  Eqg8 D~ I\22 LjI::}>$Ghm -G2qrr^<^<qr2<^!8 B qhR" I>6ihk d  17DmHH2qss^6^6qs27dt  (  z   A YV<|@i9z ^ G nKI2qtt^0^0qt29 q< OWF F j> A4Ih F_3!86 iM>o m tJ2quu^)^)qu2,Np np} ;$guHf G 80 n ! +K2qvv^#^#qv2A+  eN^ a^] L:s B5k 9|LVRbt$K Ih]L2qww^^qw2tsX9H 4! S~[m "";w+FJGDMRnoBA }zV p-dM2qxx^^qx2 !BK $ l<  6 Zc}or5OPhH> o[ 9 N2qyy^^qy2#|0  _? M )*{Y+@/ JJ 8]6Y>}O2qzz^ ^ qz2)z~f+= rt  J}wP;>x+{y{"k4  `K?[~ =P2q{{^^q{2Ud2Ee  x  ZC[hr Y%ax`{vi'J72z h>j! } T1x@ Q2q||^#^#q|2Fm' `]jO >0fKY D 'w1 -ql+b&-^ok@6Brkk^_ݦ^_ݦrk6BEW 9   }^v'  b Ex.-]D7;f|z^59z%A6Crll^Yݭ^Yݭrl6C"dU , _ xN ( L' _'O;ZdP VB6Drmm^Sݴ^Sݴrm6D_.+9 m3 Z { T!w[ tGqV8 Z QWw? `2IX;"o %w hS94wC6Ernn^Mݻ^Mݻrn6EJn>{e gn YIH  - Tg B&MV7 .wD6Froo^G^Gro6F=B_k;D "9^mf~EE|Y ?V["Zz6'd\FE6Grpp^A^Arp6G@mQ8un`S 9 4&^4;0MGD i1g 3 d ]F6Hrqq^;^;rq6H}oc+! !EXU dOHXg :A;P.] _= }Y1 iG6Irrr^5^5rr6I8s   C| m yV+^ ;6UBE;UTk. LX NsH6Jrss^/^/rs6Jcd o m n F 7{ kq% > 7bi MlI6Krtt^)^)rt6K ~rw7 - r| s}3* ssZ pe J6Lruu^"^"ru6L?:2.  2  t  { KrAj NV. ixzv[aDhK6Mrvv^^rv6Men R{  ,] =J|1jt"gz#fEdc  fK].L6Nrww^^rw6N V hHr @ )N6Pryy^ ^ ry6PjN9# w i[ m v v~/"<1(6R  1 O6Qrzz^^rz6Q(Tc_ F|7! 0hjIC}, V OD673- W6 !P6Rr{{^^r{6RZqk3d ED 9 5%HpL S ) Kr`WU<"bO&]1aSQ6Sr||^^r|6Shmg3i , #=P 2!SKJFS!fw l 7w x c2z8A@9skk^Xޠ^Xޠsk9vh1, ey S j )<&jf_vep)aP ,t_A9sll^Rާ^Rާsl9F4P'E-( _ l =o b N&k@R`  gVm%y(KmB9smm^Lޮ^Lޮsm9YXD(5 4 +6(  I H; RIO7 H\6U`*E;sY mC9snn^F޵^F޵sn9l w " , H j 9\n[ $~mQ@= ^U G4   #DND9soo^@޼^@޼so9^taVc 4 y t~ Yh !8S(kJ}%sBp$ < #].E9spp^:^:sp9>%R k  ` @  u P5~Q"Z<Z;T V xS s[O &F9sqq^4^4sq9sk+ n q_ /5_@Sq !F6F)=M 5 (i S Y G:srr^.^.sr: 1 ~D 1^2;. - Y[q 4x 0 P" 9a[< LH:sss^(^(ss:vGE/C q?KyY {8Vb1P|24 3x$ #C ? Zy.T lI:stt^"^"st:0c&A *}DB :D9IN=jb_~ mrU T,K J:suu^^su:EN|) g wH ~ > fGpvGr5fd Pa?aN $pLRxK:svv^^sv:((4l5, :O  Qa>{YPM)~R|~nzt4 v. tL:sww^^sw:p2I\T E.) "Md o +DNc822xP W 7.Dp O\M:sxx^ ^ sx:~q G[n I KGK *3 _!, cL-zN:syy^^sy: *g8c _40^ 4f >hD JP|GRtEc.0O:szz^ ^ sz:8Z7  A:N ]lOBTdzD D%"u?D!K h )pSP: s{{^^s{: | 7 V r d 8?Baa^P6e " P-(n Q: s||^^s|: sh  A Kx% 4b 7M[5$I%h+  w U;Z@=tkk^Qߚ^Qߚtk=#]D  v 5}cBEGTAGU6f5 /'Q wu x NN=t6f A=tll^Kߡ^Kߡtl=3A8j5  <  )2*rp  p{r k$(@B=tmm^Eߨ^Eߨtm=O / yHSII r.\xC  I34l >iL9vC=tnn^?߯^?߯tn=5$l I yP| 4fg ud {/& k_n; ,D=too^9߶^9߶to=w V 5j=lGEIZ\L 0 00rE=tpp^3߽^3߽tp=ctu0 n QS5y e5kNz esHuyq~ Z U Uk<F=tqq^-^-tq=MJ~T m- 1ne21 Y'0 \ lI K" LxG=trr^'^'tr=@MppT R 1"I # >1 uP4<;LlMb  pH=tss^!^!ts=?N I(-.L."? c Qm*Z R C7 nP&I=ttt^^tt=Wo}!%97 @vs ,dL  .[F ) 8D3 hJ=tuu^^tu=)K> fvkRvUv~ZYt ~'{BPm|^;K=tvv^^tv=l5&ML BQ [`o! lWj D [6S r T L=tww^^tw=`r)bap 4 Y   hjdr6e~SjN=tyy^^ty= "~ r! @ 0'F?e ;'6uW? Uw  3 >bd) O=tzz^^tz=Cl#k 9 O ^(M^@ ;]907u/ry$FE[s :P=t{{^ ^ t{=t<W no pleM2LoC*J Mv) k4Q=t||^^t|=N4I 'v{F ran8z,pY D },@Agukk^J^JukAgth1l<I r @=qhGnJ`lI: \ t%TtAAhull^D^DulAhg *  S )mq= y}flBAiumm^>^>umAi fC\+ N| a ! =/-M6 H'Aa ~x[bQoG1d QCAjunn^8^8unAj_g~/*}  W87191[Fhpo s|B rS 2l @-/9DAkuoo^2^2uoAkP Z  jL7'f+ #WYs2c Bsa  VAF:b OlaEAlupp^,^,upAl,2waOI |4 % v}L"9  =)iVCz^cO0 FAmuqq^&^&uqAmb*bXEUo)vq (<e^ 4C eta&DH,q%GAnurr^ ^ urAn Y = !~H$h F .-5+9<[FHAouss^^usAo= I*> 1j:v =3Oy3 s9 ?EUAN3|x IAputt^^utAp / R=+w?oeo J; #  SQ5  H JAquuu^ ^ uuAq]OkG2 |%R {NX.K~ KA xE[KAruvv^^uvArV2- 2 ' XH9 Htdj*"  I  z~Zdc o tLAsuww^^uwAsuI%3 c9 {_ KB[5X-jY418U 3 95  MAtuxx^^uxAt~BYH ,% [X nG @:uVSYRsV' 9+ klh "nNAuuyy^^uyAuY `' ;c u z(eZp{-PF j4 dd Z"q(OAvuzz^^uzAvz>* ] Al27 ?h/f3VeBmt4@%AEvll^=^=vlE\H eP WZ %S($I5D Uh@S ` _N-h '.BE vmm^7^7vmE >gfZ d xK { ]lh+zGGb^j6 Q"C} PtP CE!vnn^1^1vnE!iA IG? V  `Z y?. uWP("slULi DE"voo^+^+voE"P.G. a%EzD 40I oS9{}Ep5  J /EE#vpp^%^%vpE#H9[Mg  R  #z0Q  1 X$h ;l qUf FE$vqq^^vqE$/ilN}JF NwjUnj5L9)  ? _M| H. dRb 6 @GE%vrr^^vrE%N'- : QEX* 0  O 5  B>S u CYxZgiHIHE&vss^^vsE&n#V K Z /`D-F(.=e{ , ~KIE'vtt^ ^ vtE'uPh    ZA64nB_nW(X|;i _QzP# JE(vuu^^vuE(?)D y 6"h zay4*E{C^~  w & .H^pRU uKE)vvv^^vvE)kZY-CSu ? p BzA *H]Bnm 0\%Z49z  1LE*vww^^vwE*t:g  k!)f \ 2zN 4-) l IME+vxx^^vxE+EK .!`wR Wl$3SW-Cnt (f]p 8_NE,vyy^^vyE,*= c-~ fT.sB*k- "{  c~OE-vzz^^vzE-GAIJ! mm,3: p:I~  0{yAGPE.v{{^^v{E.2~  4&1B f .j5B`= n (a 6i*  5 QE/v||^^v|E/hs It4 -lko x+W Fh g(   K k:b@Hwkk^=^=wkH_ #T Fo#q%q._ l 9)4jV@l1 PAHwll^6^6wlH\-L?x&V P -hD !F>AX*K 8` mSO z(BHwmm^0^0wmH`oZZ faR 4 W -Y|EzXU fX!E q >CHwnn^*^*wnH c R  7107 3$ \-< > ('H]!6 1O tG AR DHwoo^$^$woHX4vgcw V  vP[nQZA"a49KAM1tQ DEHwpp^^wpHM9%Y53d| 8  I EQaAj / FolL Rs~FHwqq^^wqHR_];% vd`h^ B_?HB G {a<[KByR4(!Z y bGHwrr^^wrH?Js  Q 4 ]4h &3Xd lG&fyg3b =]aDY>SHHwss^ ^ wsH" 06B)gM - bD M X kc) q9'6e=woIHwtt^^wtH&K'a, / ' Dt#}_atO/az G [6I<JHwuu^^wuH)w t  G p t w[j M" 5B.sa-?8KHwvv^^wvHA3w F S ~w)6ZTzy2a +_>w KS[LHwww^^wwHGt>M sY G $ T~nE #Z \M@ 'rMHwxx^^wxHWXZ@   t ORmgg0 _ 2" 7!= S DuNHwyy^^wyHn UJ'nPjT&o-MJ"1 8=[J obOHwzz^^wzH@WDR u \/ *!A# sCh* 7lXJ[pCPHw{{^^w{HA] G g5l 9 )(aG;t)c37]KR T0(QHw||^^w|Hmj" y * 3cfpQ}; (t x; d(wE 6zDe(hs>@Lxkk^6^6xkL1SFtSqG  4j h%T M A%U< '9:OHALxll^/^/xlL@9Jw  UgX[748I;OD%`|]yeF ){VeuBLxmm^)^)xmLi6 ^nr - MN;-9 h i %N ][_TCLxnn^#^#xnLtL1+ .{ \Kb[ we }MP C u,rS 4 } DLxoo^^xoL#F1 n? ^]{O< d B 5 #OV m-_ x~ELxpp^^xpLZb I YcxI?db/ 1 /mBb e6x2.RCFLxqq^^xqLd|9 3  q w- Qu HSW%79 )yt fDr aGLxrr^ ^ xrL }4% uB!xR Je p=( i .yC 15HLxss^^xsLa3 A) j]@>}cQW |< d ,1l b7 ,fILxtt^^xtLYH4  Tr,K ZW* `{>Es H!> Oy&i; 2JLxuu^^xuL*-(W rj x  ( QK-utYk=? S v; &e3 b}KLxvv^^xvLcD-;:J dF ?)P X[:Mv5N)  gLLxww^^xwL@bTU3| %q; &]%'>:OLxzz^^xzL1~K |P 3 L'w#"F[M ^ (+`- NH = a ^PLx{{^^x{L9Zh |n - ^ i?&"wZqK<:u l <3 (  cQLx||^^x|L[b (Z { A yqpb\' 47S ~p@PCykk^/|^/|ykPCuY{o u `KGrBa+hg&1 A/)3:3eU s^4}APDyll^(^(ylPD 1u?~r @A)"a W eRI*Q^ (:BPEymm^"^"ymPEWzj\`v`& N w B#0QKSZ2 uH) ~X k?ECPFynn^^ynPF<{yY  ) }~ccv"uJ.M [eW : U-P/e hDPGyoo^^yoPG<nl.>C MlKJC5s"0=T)uQ(?EPHypp^^ypPHD3y) q  "'uZ t}eU_Uj0y-wB 6E;+ XFPIyqq^ ^ yqPIQat  I{D  X%t"a  +([#+!fN GYGPJyrr^^yrPJ  %x  SF\[ u RZ `HPKyss^^ysPKqoF'% y6 6 M (%.Gj *&pI i~rIPLytt^^ytPL&R@XOu Q \d # 2 4L= /)AV I Pj ! 3) vJPMyuu^^yuPMG@ " 9U K vK`PF fVZ%& ASbKPNyvv^^yvPN~b@  - C5+~&8dUD _Nvp='zLPOyww^^ywPOE \^O!/tg  )4 l"{ >  0wOB`MPPyxx^^yxPPXX &H =^ 6K}S1p#k%3Ky  pe ,:NPQyyy^^yyPQwBNT_<7 )5yQ Q% t:DpWd 9B KAD OPRyzz^^yzPR(f ; Sk{ -8S75I~ 1DPPSy{{^^y{PSnCF# u tnD] 6Ci  P11KBQPTy||^^y|PT ?Bo_   =C RtokuKU -R  o^ bv@Szkk^(v^(vzkS_5Heb &' [ lZ mqBn2~[4VvK9s ASzll^!}^!}zlSy[ o9_T6 >2 / S ytL\or lbBSzmm^^zmS]p 9 %xU/h@9VO uiqw 6`N PCSznn^^znS%0yo%x 4 rn`4EbNRs J_+ RDSzoo^^zoSsTHiEPhzn6 Ps 3 x &#BneL(W obqf`jcr ESzpp^ ^ zpSrA 4,!FC-< -?  d> ; FTzqq^^zqTQ.B%G   +^v | !N`=e]u GTzrr^^zrT_q*in _P cg YObF^ K U{v*/|# . gTHTzss^^zsTB$ 2)[+v>Y[ > X${ &K M&kS 2>ITztt^^ztT{=2 + FK D)H*r KR_^[S +JF_+ FcPE55JTzuu^^zuTN Xc7*j )Qc8*mmE K,,k> bKTzvv^^zvT 1 3 & ?I o$u _]%W vZ6Nk/LTzww^^zwT<%h&A %@  9y Qe [R$>f$MTzxx^^zxTpX,\  ,$ )H]ew dw O0h  wIoU NTzyy^^zyT 0%a ,BxX Yj~P 1?(OT zzz^^zzT GRBB~ aaL  $Lj$=#P vurJzG[ w  PT z{{^^z{T !L f\Bv d O/ KO 47n I"QT z||^^z|T 9 c e^  / V G1'T ?!*`RC } j1W d<@W{kk^!o^!o{kW !J7  oN! 4gYAtQ=F cCr{XAW{ll^v^v{lW nlE] ]kg5|EQV?$ jRd _;b ^}BW{mm^}^}{mW /X\  ^dAD 40K,9>aZ !z RpA>M  CW{nn^^{nW]~3v  QIY~@!(Ph4iG"$y O m~'_DW{oo^^{oWULA`E.4 i)7MS="`F"6@  S ve x52EW{pp^^{pW)TA z%< n 9X RONV\. pS V3 \vC &4wFW{qq^^{qW*g Qr 9} #0q| TEGC5 nGW{rr^^{rWH3 I/Ez>-Tsn >aUy:O O)R 3= J7HW{ss^^{sW"8"{ / ?-uBH dBVB IW{tt^^{tWE"=899;.U x Y5IBy<= ! l D + }FA>(r +JW{uu^^{uWSQq{aw & p gZ  # i Q:;8% %e( + 7wKW{vv^^{vW2h;CZ1  gHm9 8ct4JHL O dD`YX\ 0LW{ww^^{wWa  HKGW Ygpj,R nv @ < ^z~ :MW{xx^^{xW tI[  Z t]@*S :UKr s  g7$ ]i1A3aQNW{yy^^{yW)30~+X #Z( au.nk ' @R d0%w D% /OW{zz^^{zWa | %JZ! ] ZU-jyQo ` =v7q h PW{{{^^{{Wt"zX 1 y _ q^ ~vv_i?C n"`lK) y rpQW{||^^{|Wpe6 } %r M?E z-c\$z/0^)N j kd/[W@[h|kk^i^i|k[hH# )!jU )o rNmmcm l &Rj (IgA[i|ll^p^p|l[iLBx o ag]WNfhOO6 j A E wx " u+~HJB[j|mm^ w^ w|m[j ^zR_ AFyKG^e w I"d {- ~C[k|nn^~^~|n[k '  s#"S7KN >h }lExX |D[l|oo^^|o[ln L  , ! KKW6-!6 5`5 wo1 qE[m|pp^^|p[m" n   ! TQXH^5.$dU,:F[n|qq^^|q[n5,Ma -9 N z=H: 2E5EkW} 6J[r|uu^^|u[r}yqPL  #LLL *(:Z%9g E! +EV K[s|vv^^|v[s L,  Usx>8Zz< ?[L[t|ww^^|w[t1"Kl - NHC _ 1RL8Kf F\O aRP 4{L wg M[u|xx^^|x[ug02 ]& ; vra>D7tGpc f:_-L C N[v|yy^^|y[vqU)b^P_yGa4 - 4^ dM>dyZO[w|zz^^|z[wi <g dpK x<$mI . E d8AH~ EiK @ P[x|{{^^|{[xQ)_Z_ PPH s,u |S: y%ts2_ j l& eEeQ[y|||^^||[y  bT q[ E<n 5aZ ~:5 & W 1@_}kk^c^c}k_K)3  z c>P fzQ2 wj13Em?1c#It  A_ }ll^ j^ j}l_ `Dczl GGu"(R[ 7mP )bB_!}mm^q^q}m_!t hJ q G" ` #4 YO j:> K C_"}nn^x^x}n_"Zrd,  i R F_h Y _j* 0rJ2UU G []^ !\%N /D_#}oo^^}o_#." ON5  *f5F((9"Lpp% E_$}pp^^}p_$ N [@VrRjn ,u % `s6c?+`W fF_%}qq^^}q_%Qn8s  qJ Mg ws-Z6B \B88?mW A2vU|7G_&}rr^^}r_&e={ GL E | 5j51<' | @ b jjH_'}ss^^}s_'<$'X GQy i+ >roo]Pu\Fk +?\ @ >~ O" I_(}tt^^}t_(#* x BJ J q " uL) pV)@7 96Ur6~J_)}uu^^}u_)z:N Z']h i> wV A!\r~k6?OYTK_*}vv^^}v_* ez0$W\AX iVSW0T%a gM1L_+}ww^^}w_+8 n Cm , S6o=tN :1x5sK/F _lN_-}yy^^}y_-6]Ojej s@wQ8:R:y'_ @WQx ccvG'~ cZ$O_.}zz^^}z_.5m=6 K 4=FS" j/MCRi.h@N rb Zs">B5 P_/}{{^^}{_/TCo Ch  ' tfR@b~kk^ ]^ ]~kb' Y JXQrP oEq P9F!| 2"_N J Ab~ll^d^d~lb||tB4 LT`3 ]XE Vf  LX q okBb~mm^k^k~mbyli*i M  Hn~IwZp_  <YB5C Cb~nn^r^r~nbdNco[ : ` Qs +[  >pP _^ e { 0,O Db~oo^y^y~obRU_z \)t U{ f[Y 9UK]ZjBbug z&QpEb~pp^^~pbHoHK Tg! . ;uab?&&$6Gn?  Mg;Fb~qq^^~qb B  >iA< '^uLb 5t/ODgqUJ .1Gb~rr^^~rbFV Ok '  |U:GqAFrhDKpiPn 4_Hb~ss^^~sbN*  2\ 8khO k X).Jc NqtEiK6 lIb~tt^^~tb#K!  @ $2\ fU I +A AP  b ! h_Jb~uu^^~ubt - |`r$&B ~ [ ?/b 1_?v. ]/Yg@fkk^W^Wkfyd[ 7 { A>[{ S m; ;Zn1V*`Afll^^^^lf*&B| K:  rfOtS k Pqf Z\Bfmm^e^emfL3[SmA Q=t  f=]z' qCfnn^l^lnf .{ gx \ 9 * f gf 8 <0cxrP n2q O;pDfoo^s^sofLQu6S-<JA5i C/-!,YMLN3$<NEfpp^z^zpf=q3I   0DH ZHL$T] @b  g_ <e)OFfqq^^qf(/-MI W ;P +; xD]d)e /N{lXGfrr^^rfe]d),hR t(& n W,;W| |Aw,bE[! N2_ Hfss^^sf7 0 ]]]9) K v) 49<n4tN  >Rnt$*%dIftt^^tfr 9Q6 ) / Gn1  z tzRJ&-y(( -Jfuu^^uf?e#G c AA PZ  A '-lU_ AnKh$ =Kfvv^^vf A@7ui (v7 Fmo#  ![ V9h PKvWLfww^^wf6@,d ,o7:!}X9D{@B~ bIF!C Mfxx^^xf6d^oT @  ?K ]$~S l\1\E j9ygteKNfyy^^yfmfe/ 9 [ aS 8D%3[qex\Ofzz^^zf>F P'%lnyE'7e 5+ Q cUb S \4Tm3nPf{{^^{f&]e6 93 (7Ghu{(Zm 8qQ4T \xapQf||^^|fJo+[r%ZQs .{0& T ngLHfvS L8JI>]m@jDkk^Q^QkjD%CF>^ B a n]SQ}= vNcFLdB,2h7 <)Q`KFjJqq^{^{qjJLw:c5/" i*  ? Mx`">%Bd:C'_Hba"FV^b GjKrr^^rjK h _5VDKp  A ;pg r6HjLss^^sjL1[j  9o( ZQ gvy S"u#h} IjMtt^^tjMKJ7: 8  JY cg ]uWM mX $LXAeep HryJjNuu^^ujN & MMv {z?iSte*{['KjOvv^^vjO i} : ^Y O J 9F Fa! 9o Z+{\3.KLjPww^^wjP VTa[ &w *+ j 1EMC oiW" 1t-Yw~a@MjQxx^^xjQ 8Ip]> ) u+9n (J5 O l{97 (at<NjRyy^^yjR[22 W  : W v):h7, XMt<R!n: |*Bi~OjSzz^^zjSl{{Z  o R] HQ }ur.3  u'Sb4rPjT{{^^{jT$\ mg!Nc ?3 \9O;(]Q9QcUB SG'QjU||^^|jUvU ,F E e `S~~prrxx 1Yx8 Iaz@mkk^K^Kkm }w\ R m s W._qk 1 p UE {rBAmll^R^Rlm^: D~PS  _/~71 ~w2H8'wy!#" Fd * \Bmmm^Y^YmmC"u 7Cl )aPK_ 54!<A0$0mtR NO L Cmnn^`^`nm7t7 cc  . ? OD tm99 2fDmoo^g^gom&g,HGshzo R  bRGfPu +[jb LjFEnpp^n^npnB VBW z)p zv ]?Pj uw&Lm&T jFnqq^u^uqnWdW 9,P81 |,Wyxx{ jdX& ZhGnrr^|^|rn|2%" H-_Vy0A'b $5bII;&K!( Xic$,XDyC@mHnss^^sntTtOn  t m M" x{|\Hf*IRbKn#g2 mDXMVh) ; Intt^^tn()PS (a36'c jMi 3,WR K?xi?p 3G:A]#[`Jnuu^^unt vN'hV&}t d,Ss X2 t[? HWzKnvv^^vn* +4U 7:tM r K_n})T KA @ : n^$4?OD0aLnww^^wngzi[ ?Aj  )1F<{| y7hlR U43\*9_90Mnxx^^xn9 _ {{ $!&9s hQ\v  5+znm ]Hf4WsNn yy^^yn =JaQ 2!$Dh2 ( 7- P,7@  ?S7.On zz^^zn YHV<l  x^o,7YU soBM Y. 6 B./M 1=9PPn {{^^{n S   -Rf;2  $PE5O }Wlzk U@NrQn ||^^|n 5jJ8^` + Zn Jjs?oJ0  .6c=8:Go Z @qkk^E^Ekqkh2  5j$[i+_#P x3Db" mzl|iAqll^L^Llq2Q[,3 rq>#>PZbhKr#1AXzBY@^| Bqmm^S^Smq ILA[ 2 4" = `fOwQ S@'EK1 e!T-TM 7$lv\Cqnn^Z^ZnqMMwO/ }# K TsIc  ?K{# h4w [ 2QxDqoo^a^aoq--dm|%|s ri{" j;> hB"Rhno0 yRlEqpp^h^hpq=.^ a  SA[fd a (WI6 99L& j3_ 2MO\ +r 0Q/dFqqq^o^oqq^ fO Y Is = +~j uLxTm 2hXieS Gqrr^v^vrq9D0*G# @u#}_ 8gL  +j5 |%|Hqss^}^}sq|1, M  < G6T <<';^<4 n8lEd&3 gIqtt^^tq}% CdB>+g sg>F  +h4> 0D&IP\Jquu^^uqu%16}Te  Kf#X 3 ?z]e  Pt Kqvv^^vq| A$ G N+D^ mpf Cs~ih9V7V7v0 >Lqww^^wqviMTjd0f9B ~v Q0V X 3P R0Mqxx^^xqEouLrii& 0 \CL}@ 3`tpIR L=g0 Vy Cc`j YNqyy^^yqrB V .ZWw- ufX[D xKE}C C F w=Oqzz^^zq+G!i W  : AY  4tB 7;o 1\ #U+ X,Pq{{^^{q+U7` r v:gtbA Z9 d }7) ( X J Qq||^^|qgyKah _ o  O_K;T<+XQ  kR@CF `@uikk^?^?kuio 8A C J b/ \;kL^ Hd kM 3s$Aujll^F^FlujL  yT#(;( K$$z&  xBukmm^M^MmukXtSNC l E1aO%QaV t - k53K F9@MCulnn^T^TnulejS h ; pgl x|AnN4g#Gw} q;]FW?Dumoo^[^[oum~i\-;{ >}i yEunpp^b^bpun;tZ'h;d Z 9&noq! _iM] w.;W>|Lx f. ~Fuoqq^i^iquo @sO "   z}W~ 3V Prh2 b @+P  k p7!sGuprr^o^orupK9W >O:79XW$HdW2xR*  KHuqss^v^vsuqR9  \R= C gj #_ 7q5w]H XIurtt^}^}turGB-` f x(wcX:CCJ # /FDRnKlJusuu^^uusi]QlG & 7lO'I y  G(7z  l;  33$I QHD@Kutvv^^vut&3  xQS  LB .%w]9g ib.s 7 S&Un - Luuww^^wuuc) v eH=  d"`7Lt {R Ku*~Pl ~k ;Muvxx^^xuv+ 4 P@O=w v yB=- ~mzl7GXZnNuwyy^^yuw&oll r Ag  8 !CR& GkN jG~uN2Ouxzz^^zuxQ >  k P9 f> kXm[_( wlPPuy{{^^{uy<2  2 }sK` A .: Pd B@Quz||^^|uz6_I  5c mn T4 ~ ,LfRD0  wo ; a5]@y kk^8^8ky YpM r  : 6[Jvhy% c  _@*k  EtAy!ll^?^?ly!f!s USPUzM) }{FWRE9,]j - R- $h  By"mm^F^Fmy"t;w  :! s\SoPcdhNFp(h(or5 fZ,_Cy#nn^M^Mny#Zg !    Jf wdB( >!X  (9 ,h0 {4^jDy$oo^T^Toy$219Lg\oa K = 7Ey%pp^[^[py%'P1vY E} )8n,i1NsH `yM +FZ -)W]-Fy&qq^b^bqy&b B4   @ ` v| &t5 R _0!} ;&  Xy:Q Gy'rr^i^iry'oe4&%Jp C "QsHdy Ww o50 ,m[<Hy(ss^p^psy(GD/z j & KF Ic  rP $0 5./Y2 Iy)tt^w^wty)&s(yc)j s E( ,$Sp}:i  HV U% U q>>~2sDjY _ LE 4jz JLy,ww^^wy,D=6j<) <]q R %Y F59O0e l~) 1fMy-xx^^xy-z]1*0'YF 0p_KG>]= #?= f g!M Ny.yy^^yy.%zp mjUn~ ;vX ZZ  Mh >D 8Oy/zz^^zy/CU;|& . =5 R^q! u) . I {\aOo RPy0{{^^{y0Q <"gbN_4aS :m@e (P ZD^}>Qy1||^z^z|y1&7  j !_vwA ~O h Y! CW9 @|kk^2^2k|2 G ]  99 4Bj G cHGxvXI(' r5A|ll^9^9l|omqS{N  NJ aX&  O 9 LYd v[ 4!d81nj2B|mm^@^@m| z `_@ G U', mw{w W [A M:M}C|nn^G^Gn|jx ok| XrQ<7+%CL+9 ;9 :D|oo^N^No|8|   1#L< }N h0 p5ko6% ] $ E|pp^U^Up|O v 1e; I! Q6%n"; ^jb F|qq^\^\q|< ,pf z Zp2AMfP7iR # P 31 ]rWvajwG|rr^c^cr|Q$tM{~'r zZq SO /l  `PQ 3a NH'M;BH|ss^j^js| cB J r,x q :  \w pvI|tt^q^qt|aK [ Znq" @ */a !I=G 5L n M|xx^^x|U8QCTy $Z^' srjV 5 Ic\ .z ylad IQN|yy^^y|a{ khD [9 } 6: MBk0By (f O|zz^^z|Ho<, `NI)h fKNdQmO Ct,9j''P|{{^y^y{|G}* j}I$ W4 cYAdzx!Q|||^s^s||[oK0G ' j 0YJk evzu9]# F R$segyio-1.8.3/test-data/inv-small-ps.sgy0000664000372000037200000002412013407674361017372 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  BBBBBBBBBBBhBhBhBhBhBhBhBhBhBhBBB B!B!B"B#B#B$B%BhBhBh Bh Bh!Bh"Bh"Bh#Bh$Bh$BBBBBBBBBBBhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBB B!B!B"B#B#B$B%BgBgBg Bg Bg!Bg"Bg"Bg#Bg$Bg$BBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBB B!B!B"B#B#B$B%BfBfBf Bf Bf!Bf"Bf"Bf#Bf$Bf$BBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBeBeBeBeBeBeBeBeBeBeBBB B!B!B"B#B#B$B%BeBeBe Be Be!Be"Be"Be#Be$Be$BBBBBBBBBBBeBeBeBeBeBeBeBeBeBesegyio-1.8.3/test-data/small-ps-dec-xl-inc-il-off.sgy0000664000372000037200000002412013407674361021673 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  BeBeBeBeBeBeBeBeBeBeBBBBBBBBBBBeBeBe Be Be!Be"Be"Be#Be$Be$BBB B!B!B"B#B#B$B%BeBeBeBeBeBeBeBeBeBeBBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBfBfBf Bf Bf!Bf"Bf"Bf#Bf$Bf$BBB B!B!B"B#B#B$B%BfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBgBgBg Bg Bg!Bg"Bg"Bg#Bg$Bg$BBB B!B!B"B#B#B$B%BgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBhBhBh Bh Bh!Bh"Bh"Bh#Bh$Bh$BBB B!B!B"B#B#B$B%BhBhBhBhBhBhBhBhBhBhBBBBBBBBBBsegyio-1.8.3/test-data/text.sgy0000664000372000037200000000702013407674361016034 0ustar travistravis@@z@aa@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@k@@z@@k@@z@@@@@@@@@@@@@@@@@@z@~M`]@M@]k~M`]@M@]@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@K@k@z@@@@@@@@@@@@@@@@@@@@@@@@@z@@k@@k@`@Kk@`@K@@@@@@@@@@@@z@@k@@k@`@Kk@`@K@@@@@@@@@@@z@@k@@k@`@Kk@`@K@@@@@@@@@@z@@k@@k@`@Kk@`@K@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@`@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ segyio-1.8.3/test-data/left-small.sgy0000664000372000037200000003441013407674361017113 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2dA33A3=A3HA3RA3]A3gA3rA3|A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A4$A4.A49A4CA4NA4XA4cA4mA4xA4A4A4A4A4A4A4A4A4A4A4A4A5A5 A5A5 A5*A55cA\)A\3A\=A\HA\RA\]A\gA\rA\|A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A]$A]/A]9A]DA]NA]YA]cA]nA]xA]A]A]A]A]A]A]A]A]A]A]A]A^A^ A^A^ A^*bAA)A3A>AHASA]AhArA}AAAAAAAAAAAAAAAA$A/A9ADANAYAcAnAxAAAAAAAAAAAAAA AA aAAA)A4A>AHASA]AhArA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA A`A AAA)A4A>AIASA^AhAsA}A׈AגAםAקAײA׼AAAAAAAAAA%A/A:ADAOAYAdAnAyA؃A؎AؘAأAحAظAAAAAAAA dA#33A#3=A#3HA#3RA#3]A#3gA#3rA#3|A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#4A#4A#4A#4$A#4.A#49A#4CA#4NA#4XA#4cA#4mA#4xA#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#5A#5 A#5A#5 A#5*A#55cA#\)A#\3A#\>A#\HA#\SA#\]A#\hA#\rA#\|A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#]A#]A#]A#]$A#]/A#]9A#]DA#]NA#]YA#]cA#]nA#]xA#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#^A#^ A#^A#^ A#^*bA#A#)A#3A#>A#HA#SA#]A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#$A#/A#9A#DA#NA#YA#cA#nA#xA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# aA#A#A#)A#4A#>A#IA#SA#^A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#`A# A#A#A#)A#4A#>A#IA#SA#^A#hA#sA#}A#׈A#גA#םA#קA#ײA#׼A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#؃A#؎A#ؘA#أA#حA#ظA#A#A#A#A#A#A#A# dA333A33=A33HA33RA33]A33gA33rA33|A33A33A33A33A33A33A33A33A33A33A33A33A34A34A34A34$A34.A349A34CA34NA34XA34cA34mA34xA34A34A34A34A34A34A34A34A34A34A34A34A35A35 A35A35 A35*A355cA3\)A3\3A3\>A3\HA3\SA3\]A3\hA3\rA3\|A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3]A3]A3]A3]$A3]/A3]9A3]DA3]NA3]YA3]cA3]nA3]xA3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3^A3^ A3^A3^ A3^*bA3A3)A33A3>A3HA3SA3]A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3$A3/A39A3DA3NA3YA3cA3nA3xA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 aA3A3A3)A34A3>A3IA3SA3^A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3`A3 A3A3A3)A34A3>A3IA3SA3^A3hA3sA3}A3׈A3גA3םA3קA3ײA3׼A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3؃A3؎A3ؘA3أA3حA3ظA3A3A3A3A3A3A3A3 dAC33AC3=AC3HAC3RAC3]AC3gAC3rAC3|AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC4AC4AC4AC4$AC4/AC49AC4DAC4NAC4YAC4cAC4nAC4xAC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC5AC5 AC5AC5 AC5*AC55cAC\)AC\3AC\>AC\HAC\SAC\]AC\hAC\rAC\}AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC]AC]AC]AC]$AC]/AC]9AC]DAC]NAC]YAC]cAC]nAC]xAC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC^AC^ AC^AC^ AC^+bACAC)AC3AC>ACHACSAC]AChACrAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC aACACAC)AC4AC>ACIACSAC^AChACsAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC AC`AC ACACAC)AC4AC>ACIACSAC^AChACsAC}AC׈ACגACםACקACײAC׼ACACACACACACACACACAC%AC0AC:ACEACOACZACdACoACyAC؃AC؎ACؘACأACحACظACACACACACACACAC dAS33AS3=AS3HAS3RAS3]AS3gAS3rAS3|AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS4AS4AS4AS4$AS4/AS49AS4DAS4NAS4YAS4cAS4nAS4xAS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS5AS5 AS5AS5 AS5*AS55cAS\)AS\3AS\>AS\HAS\SAS\]AS\hAS\rAS\}AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS]AS]AS]AS]$AS]/AS]9AS]DAS]NAS]YAS]cAS]nAS]xAS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS^AS^ AS^AS^ AS^+bASAS)AS3AS>ASHASSAS]AShASrAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS aASASAS)AS4AS>ASIASSAS^AShASsAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS AS`AS ASASAS)AS4AS>ASIASSAS^AShASsAS}AS׈ASגASםASקASײAS׼ASASASASASASASASASAS%AS0AS:ASEASOASZASdASoASyAS؃AS؎ASؘASأASحASظASASASASASASASAS segyio-1.8.3/test-data/small-ps-dec-il-off-inc-xl.sgy0000664000372000037200000002412013407674361021673 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  BBBBBBBBBBBhBhBhBhBhBhBhBhBhBhBBB B!B!B"B#B#B$B%BhBhBh Bh Bh!Bh"Bh"Bh#Bh$Bh$BBBBBBBBBBBhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBB B!B!B"B#B#B$B%BgBgBg Bg Bg!Bg"Bg"Bg#Bg$Bg$BBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBB B!B!B"B#B#B$B%BfBfBf Bf Bf!Bf"Bf"Bf#Bf$Bf$BBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBeBeBeBeBeBeBeBeBeBeBBB B!B!B"B#B#B$B%BeBeBe Be Be!Be"Be"Be#Be$Be$BBBBBBBBBBBeBeBeBeBeBeBeBeBeBesegyio-1.8.3/test-data/small-ps-dec-il-xl-off.sgy0000664000372000037200000002412013407674361021124 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  BBBBBBBBBBBhBhBhBhBhBhBhBhBhBhBBB B!B!B"B#B#B$B%BhBhBh Bh Bh!Bh"Bh"Bh#Bh$Bh$BBBBBBBBBBBhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBB B!B!B"B#B#B$B%BgBgBg Bg Bg!Bg"Bg"Bg#Bg$Bg$BBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBB B!B!B"B#B#B$B%BfBfBf Bf Bf!Bf"Bf"Bf#Bf$Bf$BBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBeBeBeBeBeBeBeBeBeBeBBB B!B!B"B#B#B$B%BeBeBe Be Be!Be"Be"Be#Be$Be$BBBBBBBBBBBeBeBeBeBeBeBeBeBeBesegyio-1.8.3/test-data/straight-small.sgy0000664000372000037200000003441013407674361020006 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2ddA33A3=A3HA3RA3]A3gA3rA3|A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A4$A4.A49A4CA4NA4XA4cA4mA4xA4A4A4A4A4A4A4A4A4A4A4A4A5A5 A5A5 A5*A55dcA\)A\3A\=A\HA\RA\]A\gA\rA\|A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A]$A]/A]9A]DA]NA]YA]cA]nA]xA]A]A]A]A]A]A]A]A]A]A]A]A^A^ A^A^ A^*dbAA)A3A>AHASA]AhArA}AAAAAAAAAAAAAAAA$A/A9ADANAYAcAnAxAAAAAAAAAAAAAA AA daAAA)A4A>AHASA]AhArA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA Ad`A AAA)A4A>AIASA^AhAsA}A׈AגAםAקAײA׼AAAAAAAAAA%A/A:ADAOAYAdAnAyA؃A؎AؘAأAحAظAAAAAAAA cdA#33A#3=A#3HA#3RA#3]A#3gA#3rA#3|A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#4A#4A#4A#4$A#4.A#49A#4CA#4NA#4XA#4cA#4mA#4xA#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#5A#5 A#5A#5 A#5*A#55ccA#\)A#\3A#\>A#\HA#\SA#\]A#\hA#\rA#\|A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#]A#]A#]A#]$A#]/A#]9A#]DA#]NA#]YA#]cA#]nA#]xA#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#^A#^ A#^A#^ A#^*cbA#A#)A#3A#>A#HA#SA#]A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#$A#/A#9A#DA#NA#YA#cA#nA#xA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# caA#A#A#)A#4A#>A#IA#SA#^A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#c`A# A#A#A#)A#4A#>A#IA#SA#^A#hA#sA#}A#׈A#גA#םA#קA#ײA#׼A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#؃A#؎A#ؘA#أA#حA#ظA#A#A#A#A#A#A#A# bdA333A33=A33HA33RA33]A33gA33rA33|A33A33A33A33A33A33A33A33A33A33A33A33A34A34A34A34$A34.A349A34CA34NA34XA34cA34mA34xA34A34A34A34A34A34A34A34A34A34A34A34A35A35 A35A35 A35*A355bcA3\)A3\3A3\>A3\HA3\SA3\]A3\hA3\rA3\|A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3]A3]A3]A3]$A3]/A3]9A3]DA3]NA3]YA3]cA3]nA3]xA3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3^A3^ A3^A3^ A3^*bbA3A3)A33A3>A3HA3SA3]A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3$A3/A39A3DA3NA3YA3cA3nA3xA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 baA3A3A3)A34A3>A3IA3SA3^A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3b`A3 A3A3A3)A34A3>A3IA3SA3^A3hA3sA3}A3׈A3גA3םA3קA3ײA3׼A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3؃A3؎A3ؘA3أA3حA3ظA3A3A3A3A3A3A3A3 adAC33AC3=AC3HAC3RAC3]AC3gAC3rAC3|AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC4AC4AC4AC4$AC4/AC49AC4DAC4NAC4YAC4cAC4nAC4xAC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC5AC5 AC5AC5 AC5*AC55acAC\)AC\3AC\>AC\HAC\SAC\]AC\hAC\rAC\}AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC]AC]AC]AC]$AC]/AC]9AC]DAC]NAC]YAC]cAC]nAC]xAC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC^AC^ AC^AC^ AC^+abACAC)AC3AC>ACHACSAC]AChACrAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC aaACACAC)AC4AC>ACIACSAC^AChACsAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACa`AC ACACAC)AC4AC>ACIACSAC^AChACsAC}AC׈ACגACםACקACײAC׼ACACACACACACACACACAC%AC0AC:ACEACOACZACdACoACyAC؃AC؎ACؘACأACحACظACACACACACACACAC `dAS33AS3=AS3HAS3RAS3]AS3gAS3rAS3|AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS4AS4AS4AS4$AS4/AS49AS4DAS4NAS4YAS4cAS4nAS4xAS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS5AS5 AS5AS5 AS5*AS55`cAS\)AS\3AS\>AS\HAS\SAS\]AS\hAS\rAS\}AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS]AS]AS]AS]$AS]/AS]9AS]DAS]NAS]YAS]cAS]nAS]xAS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS^AS^ AS^AS^ AS^+`bASAS)AS3AS>ASHASSAS]AShASrAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS `aASASAS)AS4AS>ASIASSAS^AShASsAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS AS``AS ASASAS)AS4AS>ASIASSAS^AShASsAS}AS׈ASגASםASקASײAS׼ASASASASASASASASASAS%AS0AS:ASEASOASZASdASoASyAS؃AS؎ASؘASأASحASظASASASASASASASAS segyio-1.8.3/test-data/small-lsb.su0000664000372000037200000002537013407674361016573 0ustar travistravis2?虙?@??蚙?8???8???0??؝?0??؞?(??П? ?x?Ƞ? ?p?ȡ??p???h???h???`???`???X???X???P??2H???@???8???8???0???0???(???(?x?? ?x?? ?p???p???h???`???`???X???X???P?2(?H)?)?)?@*?*?*?@+?+?+?8,?,?,?8-?-?-?0.?.?.?0/?/?/?(0?x0?0? 1?x1?1? 2?p2?2?3?p3?3?4?h4?4?5?h5?5?6?`6?6?7?`7?7?8?X8?8?9?2p?p?Hq?q?q?@r?r?r?@s?s?s?8t?t?t?8u?u?u?0v?v?v?0w?w?w?(x?x?x?(y?xy?y? z?xz?z? {?p{?{?|?p|?|?}?h}?}?~?`~?~??`???X??2P???H???H???@??軞?@??輞?8??ཞ?8??ྞ?0??ؿ?(???(?x?? ž?xž?ž? Þ?pÞ?Þ?Ğ?pĞ?Ğ?Ş?hŞ?Ş?ƞ?hƞ?ƞ?Ǟ?`Ǟ?Ǟ?Ȟ?`Ȟ?2 @ @ @H @t @ @ @ @ @D @p @ @ @ @ @@ @l @ @ @ @ @< @h @ @ @ @ @8 @` @ @ @ @ @4 @\ @ @ @ @ @0 @X @ @ @ @ @, @T @ @ @ @2p @p @p @ q @Lq @tq @q @q @q @r @Dr @pr @r @r @r @s @@s @ls @s @s @s @t @\@R\@h\@|\@\@\@\@\@\@\@]@$]@:]@N]@d]@x]@]@]@]@]@]@]@ ^@ ^@4^@J^@^^@t^@^@^@^@^@^@^@_@_@0_@F_@Z_@p_@_@_@_@_@_@_@`@`@,`@2@(@>@R@h@|@@@@Ю@殇@@@$@:@N@d@x@@@@̯@⯇@@ @ @6@J@`@t@@@@Ȱ@ް@@@@0@F@Z@p@@@@ı@ر@@@@2ff@zf@f@f@f@f@f@f@g@"g@8g@Lg@bg@vg@g@g@g@g@g@g@ h@h@4h@Hh@^h@rh@h@h@h@h@h@h@i@i@.i@Di@Xi@ni@i@i@i@i@i@i@j@j@*j@@j@Tj@jj@2R@f@|@@@@и@並@@@$@8@N@b@x@@@@ʹ@๦@@ @@4@H@^@r@@@@ƺ@ܺ@@@@0@D@Z@n@@@@»@ػ@컦@@@,@@@V@2< @R @f @| @ @ @ @ @ @ @ @$ @8 @N @b @x @ @ @ @ @ @ @ @ @4 @J @^ @t @ @ @ @ @ @ @ @ @0 @D @Z @n @ @ @ @ @ @ @@@,@@@2(\@>\@R\@h\@|\@\@\@\@\@\@\@]@$]@:]@N]@d]@x]@]@]@]@]@]@]@ ^@ ^@4^@J^@^^@t^@^@^@^@^@^@^@_@_@0_@F_@Z_@p_@_@_@_@_@_@_@`@`@,`@2@(@>@R@h@|@@@@Ю@殧@@@$@:@N@d@x@@@@̯@⯧@@ @ @6@J@`@t@@@@Ȱ@ް@@@@0@F@Z@p@@@@ı@ر@@@@segyio-1.8.3/test-data/small-ps-dec-off-inc-il-xl.sgy0000664000372000037200000002412013407674361021673 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  BBBBBBBBBBBeBeBeBeBeBeBeBeBeBeBBB B!B!B"B#B#B$B%BeBeBe Be Be!Be"Be"Be#Be$Be$BBBBBBBBBBBeBeBeBeBeBeBeBeBeBeBBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBB B!B!B"B#B#B$B%BfBfBf Bf Bf!Bf"Bf"Bf#Bf$Bf$BBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBB B!B!B"B#B#B$B%BgBgBg Bg Bg!Bg"Bg"Bg#Bg$Bg$BBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBhBhBhBhBhBhBhBhBhBhBBB B!B!B"B#B#B$B%BhBhBh Bh Bh!Bh"Bh"Bh#Bh$Bh$BBBBBBBBBBBhBhBhBhBhBhBhBhBhBhsegyio-1.8.3/test-data/small-ps.sgy0000664000372000037200000002412013407674361016600 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  BeBeBeBeBeBeBeBeBeBeBBBBBBBBBBBeBeBe Be Be!Be"Be"Be#Be$Be$BBB B!B!B"B#B#B$B%BeBeBeBeBeBeBeBeBeBeBBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBfBfBf Bf Bf!Bf"Bf"Bf#Bf$Bf$BBB B!B!B"B#B#B$B%BfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBgBgBg Bg Bg!Bg"Bg"Bg#Bg$Bg$BBB B!B!B"B#B#B$B%BgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBhBhBh Bh Bh!Bh"Bh"Bh#Bh$Bh$BBB B!B!B"B#B#B$B%BhBhBhBhBhBhBhBhBhBhBBBBBBBBBBsegyio-1.8.3/test-data/小文件.sgy0000664000372000037200000003441013407674361020326 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2A33A3=A3HA3RA3]A3gA3rA3|A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A4$A4.A49A4CA4NA4XA4cA4mA4xA4A4A4A4A4A4A4A4A4A4A4A4A5A5 A5A5 A5*A55A\)A\3A\=A\HA\RA\]A\gA\rA\|A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A]$A]/A]9A]DA]NA]YA]cA]nA]xA]A]A]A]A]A]A]A]A]A]A]A]A^A^ A^A^ A^*AA)A3A>AHASA]AhArA}AAAAAAAAAAAAAAAA$A/A9ADANAYAcAnAxAAAAAAAAAAAAAA AA AAA)A4A>AHASA]AhArA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA AA AAA)A4A>AIASA^AhAsA}A׈AגAםAקAײA׼AAAAAAAAAA%A/A:ADAOAYAdAnAyA؃A؎AؘAأAحAظAAAAAAAA A#33A#3=A#3HA#3RA#3]A#3gA#3rA#3|A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#4A#4A#4A#4$A#4.A#49A#4CA#4NA#4XA#4cA#4mA#4xA#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#5A#5 A#5A#5 A#5*A#55A#\)A#\3A#\>A#\HA#\SA#\]A#\hA#\rA#\|A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#]A#]A#]A#]$A#]/A#]9A#]DA#]NA#]YA#]cA#]nA#]xA#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#^A#^ A#^A#^ A#^*A#A#)A#3A#>A#HA#SA#]A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#$A#/A#9A#DA#NA#YA#cA#nA#xA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# A#A#A#)A#4A#>A#IA#SA#^A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# A#A#A#)A#4A#>A#IA#SA#^A#hA#sA#}A#׈A#גA#םA#קA#ײA#׼A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#؃A#؎A#ؘA#أA#حA#ظA#A#A#A#A#A#A#A# A333A33=A33HA33RA33]A33gA33rA33|A33A33A33A33A33A33A33A33A33A33A33A33A34A34A34A34$A34.A349A34CA34NA34XA34cA34mA34xA34A34A34A34A34A34A34A34A34A34A34A34A35A35 A35A35 A35*A355A3\)A3\3A3\>A3\HA3\SA3\]A3\hA3\rA3\|A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3]A3]A3]A3]$A3]/A3]9A3]DA3]NA3]YA3]cA3]nA3]xA3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3^A3^ A3^A3^ A3^*A3A3)A33A3>A3HA3SA3]A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3$A3/A39A3DA3NA3YA3cA3nA3xA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 A3A3A3)A34A3>A3IA3SA3^A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 A3A3A3)A34A3>A3IA3SA3^A3hA3sA3}A3׈A3גA3םA3קA3ײA3׼A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3؃A3؎A3ؘA3أA3حA3ظA3A3A3A3A3A3A3A3 AC33AC3=AC3HAC3RAC3]AC3gAC3rAC3|AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC4AC4AC4AC4$AC4/AC49AC4DAC4NAC4YAC4cAC4nAC4xAC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC5AC5 AC5AC5 AC5*AC55AC\)AC\3AC\>AC\HAC\SAC\]AC\hAC\rAC\}AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC]AC]AC]AC]$AC]/AC]9AC]DAC]NAC]YAC]cAC]nAC]xAC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC^AC^ AC^AC^ AC^+ACAC)AC3AC>ACHACSAC]AChACrAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC ACACAC)AC4AC>ACIACSAC^AChACsAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC ACACAC)AC4AC>ACIACSAC^AChACsAC}AC׈ACגACםACקACײAC׼ACACACACACACACACACAC%AC0AC:ACEACOACZACdACoACyAC؃AC؎ACؘACأACحACظACACACACACACACAC AS33AS3=AS3HAS3RAS3]AS3gAS3rAS3|AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS4AS4AS4AS4$AS4/AS49AS4DAS4NAS4YAS4cAS4nAS4xAS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS5AS5 AS5AS5 AS5*AS55AS\)AS\3AS\>AS\HAS\SAS\]AS\hAS\rAS\}AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS]AS]AS]AS]$AS]/AS]9AS]DAS]NAS]YAS]cAS]nAS]xAS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS^AS^ AS^AS^ AS^+ASAS)AS3AS>ASHASSAS]AShASrAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS ASASAS)AS4AS>ASIASSAS^AShASsAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS ASASAS)AS4AS>ASIASSAS^AShASsAS}AS׈ASגASםASקASײAS׼ASASASASASASASASASAS%AS0AS:ASEASOASZASdASoASyAS؃AS؎ASؘASأASحASظASASASASASASASAS segyio-1.8.3/test-data/right-small.sgy0000664000372000037200000003441013407674361017276 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2dA33A3=A3HA3RA3]A3gA3rA3|A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A4$A4.A49A4CA4NA4XA4cA4mA4xA4A4A4A4A4A4A4A4A4A4A4A4A5A5 A5A5 A5*A55dA\)A\3A\=A\HA\RA\]A\gA\rA\|A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A]$A]/A]9A]DA]NA]YA]cA]nA]xA]A]A]A]A]A]A]A]A]A]A]A]A^A^ A^A^ A^*dAA)A3A>AHASA]AhArA}AAAAAAAAAAAAAAAA$A/A9ADANAYAcAnAxAAAAAAAAAAAAAA AA dAAA)A4A>AHASA]AhArA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA AdA AAA)A4A>AIASA^AhAsA}A׈AגAםAקAײA׼AAAAAAAAAA%A/A:ADAOAYAdAnAyA؃A؎AؘAأAحAظAAAAAAAA cA#33A#3=A#3HA#3RA#3]A#3gA#3rA#3|A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#4A#4A#4A#4$A#4.A#49A#4CA#4NA#4XA#4cA#4mA#4xA#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#5A#5 A#5A#5 A#5*A#55cA#\)A#\3A#\>A#\HA#\SA#\]A#\hA#\rA#\|A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#]A#]A#]A#]$A#]/A#]9A#]DA#]NA#]YA#]cA#]nA#]xA#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#^A#^ A#^A#^ A#^*cA#A#)A#3A#>A#HA#SA#]A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#$A#/A#9A#DA#NA#YA#cA#nA#xA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# cA#A#A#)A#4A#>A#IA#SA#^A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#cA# A#A#A#)A#4A#>A#IA#SA#^A#hA#sA#}A#׈A#גA#םA#קA#ײA#׼A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#؃A#؎A#ؘA#أA#حA#ظA#A#A#A#A#A#A#A# bA333A33=A33HA33RA33]A33gA33rA33|A33A33A33A33A33A33A33A33A33A33A33A33A34A34A34A34$A34.A349A34CA34NA34XA34cA34mA34xA34A34A34A34A34A34A34A34A34A34A34A34A35A35 A35A35 A35*A355bA3\)A3\3A3\>A3\HA3\SA3\]A3\hA3\rA3\|A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3]A3]A3]A3]$A3]/A3]9A3]DA3]NA3]YA3]cA3]nA3]xA3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3^A3^ A3^A3^ A3^*bA3A3)A33A3>A3HA3SA3]A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3$A3/A39A3DA3NA3YA3cA3nA3xA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 bA3A3A3)A34A3>A3IA3SA3^A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3bA3 A3A3A3)A34A3>A3IA3SA3^A3hA3sA3}A3׈A3גA3םA3קA3ײA3׼A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3؃A3؎A3ؘA3أA3حA3ظA3A3A3A3A3A3A3A3 aAC33AC3=AC3HAC3RAC3]AC3gAC3rAC3|AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC4AC4AC4AC4$AC4/AC49AC4DAC4NAC4YAC4cAC4nAC4xAC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC5AC5 AC5AC5 AC5*AC55aAC\)AC\3AC\>AC\HAC\SAC\]AC\hAC\rAC\}AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC]AC]AC]AC]$AC]/AC]9AC]DAC]NAC]YAC]cAC]nAC]xAC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC^AC^ AC^AC^ AC^+aACAC)AC3AC>ACHACSAC]AChACrAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC aACACAC)AC4AC>ACIACSAC^AChACsAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACaAC ACACAC)AC4AC>ACIACSAC^AChACsAC}AC׈ACגACםACקACײAC׼ACACACACACACACACACAC%AC0AC:ACEACOACZACdACoACyAC؃AC؎ACؘACأACحACظACACACACACACACAC `AS33AS3=AS3HAS3RAS3]AS3gAS3rAS3|AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS4AS4AS4AS4$AS4/AS49AS4DAS4NAS4YAS4cAS4nAS4xAS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS5AS5 AS5AS5 AS5*AS55`AS\)AS\3AS\>AS\HAS\SAS\]AS\hAS\rAS\}AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS]AS]AS]AS]$AS]/AS]9AS]DAS]NAS]YAS]cAS]nAS]xAS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS^AS^ AS^AS^ AS^+`ASAS)AS3AS>ASHASSAS]AShASrAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS `ASASAS)AS4AS>ASIASSAS^AShASsAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS AS`AS ASASAS)AS4AS>ASIASSAS^AShASsAS}AS׈ASגASםASקASײAS׼ASASASASASASASASASAS%AS0AS:ASEASOASZASdASoASyAS؃AS؎ASؘASأASحASظASASASASASASASAS segyio-1.8.3/test-data/small-ps-dec-il-xl-inc-off.sgy0000664000372000037200000002412013407674361021673 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  BhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBhBhBh Bh Bh!Bh"Bh"Bh#Bh$Bh$BBB B!B!B"B#B#B$B%BhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBgBgBg Bg Bg!Bg"Bg"Bg#Bg$Bg$BBB B!B!B"B#B#B$B%BgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBfBfBf Bf Bf!Bf"Bf"Bf#Bf$Bf$BBB B!B!B"B#B#B$B%BfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBeBeBeBeBeBeBeBeBeBeBBBBBBBBBBBeBeBe Be Be!Be"Be"Be#Be$Be$BBB B!B!B"B#B#B$B%BeBeBeBeBeBeBeBeBeBeBBBBBBBBBBsegyio-1.8.3/test-data/small.su0000664000372000037200000002537013407674361016015 0ustar travistravis2???@???8???8???0???0???(??? ?x?? ?p???p???h???h???`???`???X???X???P?2?H???@???8???8???0???0???(???(?x?? ?x?? ?p???p???h???`???`???X???X???P2?(?)H?)?)?*@?*?*?+@?+?+?,8?,?,?-8?-?-?.0?.?.?/0?/?/?0(?0x?0?1 ?1x?1?2 ?2p?2?3?3p?3?4?4h?4?5?5h?5?6?6`?6?7?7`?7?8?8X?8?92?p?p?qH?q?q?r@?r?r?s@?s?s?t8?t?t?u8?u?u?v0?v?v?w0?w?w?x(?x?x?y(?yx?y?z ?zx?z?{ ?{p?{?|?|p?|?}?}h?}?~?~`?~??`???X?2?P???H???H???@???@???8???8???0???(???(?x?? ?x?? ?p???p???h???h?Ƹ??`?Ǹ??`2@ @ @ @ H@ t@ ͜@ @ @ @ D@ p@ Θ@ @ @ @ @@ l@ ϔ@ @ @ @ <@ h@ А@ и@ @ @ 8@ `@ ь@ Ѵ@ @ @ 4@ \@ ҈@ Ұ@ @ @ 0@ X@ ӄ@ Ӭ@ @ @ ,@ T@ Ԁ@ Ԩ@ 2@ p@ p@ p@ q @ qL@ qt@ q@ q@ q@ r@ rD@ rp@ r@ r@ r@ s@ s@@ sl@ s@ s@ s@ t@ t<@ th@ t@ t@ t@ u@ u8@ ud@ u@ u@ u@ v @ v4@ v`@ v@ v@ v@ w@ w0@ w\@ w@ w@ w@ x@ x,@ xT@ x@ x2@x@@@@ @L@t@@@@@H@p@@@@@D@l@@@@@@@h@@@@@8@d@@@@ @4@`@@@@@0@\@@@@@,@X@2@P@|@@@@$@L@x@@@@@H@p@@@@@D@l@@@@@@@h@@@@@<@d@@@@ @8@`@@@@@4@\@@@@@,@X2@\(@\P@\|@\@\@\@]$@]L@]x@]@]@]@^ @^H@^t@^@^@^@_@_D@_p@_@_@_@`@`@@`h@`@`@`@a@a<@ad@a@a@a@b @b8@b`@b@b@b@c@c4@c\@c@c@c@d@d02@L@L@L @LH@Lt@L͜@L@L@L@LD@Lp@LΘ@L@L@L@L@@Ll@Lϔ@L@L@L@L<@Lh@LА@Lи@L@L @L8@L`@Lь@LѴ@L@L@L4@L\@L҈@LҰ@L@L@L0@LX@Lӄ@LӬ@L@L@L,@LT@LԀ@LԨ@L2@Mp@Mp@Mp@Mq @MqL@Mqt@Mq@Mq@Mq@Mr@MrD@Mrp@Mr@Mr@Mr@Ms@Ms@@Msl@Ms@Ms@Ms@Mt@Mt<@Mth@Mt@Mt@Mt@Mu@Mu8@Mud@Mu@Mu@Mu@Mv @Mv4@Mv`@Mv@Mv@Mv@Mw@Mw0@Mw\@Mw@Mw@Mw@Mx@Mx,@MxT@Mx@Mx2@Nx@N@N@N@N @NL@Nt@N@N@N@N@NH@Np@N@N@N@N@ND@Nl@N@N@N@N@N@@Nh@N@N@N@N@N8@Nd@N@N@N@N @N4@N`@N@N@N@N@N0@N\@N@N@N@N@N,@NX@N2@NP@N|@N@N@N@N$@NL@Nx@N@N@N@N@NH@Np@N@N@N@N@ND@Nl@N@N@N@N@N@@Nh@N@N@N@N@N<@Nd@N@N@N@N @N8@N`@N@N@N@N@N4@N\@N@N@N@N@N,@NX2@O\(@O\P@O\|@O\@O\@O\@O]$@O]L@O]x@O]@O]@O]@O^ @O^H@O^t@O^@O^@O^@O_@O_D@O_p@O_@O_@O_@O`@O`@@O`h@O`@O`@O`@Oa@Oa<@Oad@Oa@Oa@Oa@Ob @Ob8@Ob`@Ob@Ob@Ob@Oc@Oc4@Oc\@Oc@Oc@Oc@Od@Od02@ff@fz@f@f@f@f@f@f@g@g"@g8@gL@gb@gv@g@g@g@g@g@g@h @h@h4@hH@h^@hr@h@h@h@h@h@h@i@i@i.@iD@iX@in@i@i@i@i@i@i@j@j@j*@j@@jT@jj2@R@f@|@@@@@@@@$@8@N@b@x@@@@@@@ @@4@H@^@r@@@@@@@@@0@D@Z@n@@@@@@@@@,@@@V2@ <@ R@ f@ |@ @ @ @ @ @ @ @ $@ 8@ N@ b@ x@ @ @ @ @ @ @ @ @ 4@ J@ ^@ t@ @ @ @ @ @ @ @ @ 0@ D@ Z@ n@ @ @ @ @ @ @@@,@@2@\(@\>@\R@\h@\|@\@\@\@\@\@\@]@]$@]:@]N@]d@]x@]@]@]@]@]@]@^ @^ @^4@^J@^^@^t@^@^@^@^@^@^@_@_@_0@_F@_Z@_p@_@_@_@_@_@_@`@`@`,2@@(@>@R@h@|@@@@@@@@$@:@N@d@x@@@@@@@ @ @6@J@`@t@@@@@@@@@0@F@Z@p@@@@@@@@2@ff@fz@f@f@f@f@f@f@g@g"@g8@gL@gb@gv@g@g@g@g@g@g@h @h@h4@hH@h^@hr@h@h@h@h@h@h@i@i@i.@iD@iX@in@i@i@i@i@i@i@j@j@j*@j@@jT@jj2@R@f@|@@@@@@@@$@8@N@b@x@@@@@@@ @@4@H@^@r@@@@@@@@@0@D@Z@n@@@@@@@@@,@@@V2@ <@ R@ f@ |@ @ @ @ @ @ @ @ $@ 8@ N@ b@ x@ @ @ @ @ @ @ @ @ 4@ J@ ^@ t@ @ @ @ @ @ @ @ @ 0@ D@ Z@ n@ @ @ @ @ @ @@@,@@2@\(@\>@\R@\h@\|@\@\@\@\@\@\@]@]$@]:@]N@]d@]x@]@]@]@]@]@]@^ @^ @^4@^J@^^@^t@^@^@^@^@^@^@_@_@_0@_F@_Z@_p@_@_@_@_@_@_@`@`@`,2@@(@>@R@h@|@@@@@@@@$@:@N@d@x@@@@@@@ @ @6@J@`@t@@@@@@@@@0@F@Z@p@@@@@@@@segyio-1.8.3/test-data/inv-acute-small.sgy0000664000372000037200000003441013407674361020054 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2ddA33A3=A3HA3RA3]A3gA3rA3|A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A4$A4.A49A4CA4NA4XA4cA4mA4xA4A4A4A4A4A4A4A4A4A4A4A4A5A5 A5A5 A5*A55dcA\)A\3A\=A\HA\RA\]A\gA\rA\|A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A]$A]/A]9A]DA]NA]YA]cA]nA]xA]A]A]A]A]A]A]A]A]A]A]A]A^A^ A^A^ A^*dbAA)A3A>AHASA]AhArA}AAAAAAAAAAAAAAAA$A/A9ADANAYAcAnAxAAAAAAAAAAAAAA AA daAAA)A4A>AHASA]AhArA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA Ad`A AAA)A4A>AIASA^AhAsA}A׈AגAםAקAײA׼AAAAAAAAAA%A/A:ADAOAYAdAnAyA؃A؎AؘAأAحAظAAAAAAAA deA#33A#3=A#3HA#3RA#3]A#3gA#3rA#3|A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#4A#4A#4A#4$A#4.A#49A#4CA#4NA#4XA#4cA#4mA#4xA#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#5A#5 A#5A#5 A#5*A#55ddA#\)A#\3A#\>A#\HA#\SA#\]A#\hA#\rA#\|A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#]A#]A#]A#]$A#]/A#]9A#]DA#]NA#]YA#]cA#]nA#]xA#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#^A#^ A#^A#^ A#^*dcA#A#)A#3A#>A#HA#SA#]A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#$A#/A#9A#DA#NA#YA#cA#nA#xA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# dbA#A#A#)A#4A#>A#IA#SA#^A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#daA# A#A#A#)A#4A#>A#IA#SA#^A#hA#sA#}A#׈A#גA#םA#קA#ײA#׼A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#؃A#؎A#ؘA#أA#حA#ظA#A#A#A#A#A#A#A# dfA333A33=A33HA33RA33]A33gA33rA33|A33A33A33A33A33A33A33A33A33A33A33A33A34A34A34A34$A34.A349A34CA34NA34XA34cA34mA34xA34A34A34A34A34A34A34A34A34A34A34A34A35A35 A35A35 A35*A355deA3\)A3\3A3\>A3\HA3\SA3\]A3\hA3\rA3\|A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3]A3]A3]A3]$A3]/A3]9A3]DA3]NA3]YA3]cA3]nA3]xA3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3^A3^ A3^A3^ A3^*ddA3A3)A33A3>A3HA3SA3]A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3$A3/A39A3DA3NA3YA3cA3nA3xA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 dcA3A3A3)A34A3>A3IA3SA3^A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3dbA3 A3A3A3)A34A3>A3IA3SA3^A3hA3sA3}A3׈A3גA3םA3קA3ײA3׼A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3؃A3؎A3ؘA3أA3حA3ظA3A3A3A3A3A3A3A3 dgAC33AC3=AC3HAC3RAC3]AC3gAC3rAC3|AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC4AC4AC4AC4$AC4/AC49AC4DAC4NAC4YAC4cAC4nAC4xAC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC5AC5 AC5AC5 AC5*AC55dfAC\)AC\3AC\>AC\HAC\SAC\]AC\hAC\rAC\}AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC]AC]AC]AC]$AC]/AC]9AC]DAC]NAC]YAC]cAC]nAC]xAC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC^AC^ AC^AC^ AC^+deACAC)AC3AC>ACHACSAC]AChACrAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC ddACACAC)AC4AC>ACIACSAC^AChACsAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACdcAC ACACAC)AC4AC>ACIACSAC^AChACsAC}AC׈ACגACםACקACײAC׼ACACACACACACACACACAC%AC0AC:ACEACOACZACdACoACyAC؃AC؎ACؘACأACحACظACACACACACACACAC dhAS33AS3=AS3HAS3RAS3]AS3gAS3rAS3|AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS4AS4AS4AS4$AS4/AS49AS4DAS4NAS4YAS4cAS4nAS4xAS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS5AS5 AS5AS5 AS5*AS55dgAS\)AS\3AS\>AS\HAS\SAS\]AS\hAS\rAS\}AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS]AS]AS]AS]$AS]/AS]9AS]DAS]NAS]YAS]cAS]nAS]xAS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS^AS^ AS^AS^ AS^+dfASAS)AS3AS>ASHASSAS]AShASrAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS deASASAS)AS4AS>ASIASSAS^AShASsAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASddAS ASASAS)AS4AS>ASIASSAS^AShASsAS}AS׈ASגASםASקASײAS׼ASASASASASASASASASAS%AS0AS:ASEASOASZASdASoASyAS؃AS؎ASؘASأASحASظASASASASASASASAS segyio-1.8.3/test-data/reflex-small.sgy0000664000372000037200000003441013407674361017446 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2ddA33A3=A3HA3RA3]A3gA3rA3|A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A4$A4.A49A4CA4NA4XA4cA4mA4xA4A4A4A4A4A4A4A4A4A4A4A4A5A5 A5A5 A5*A55ccA\)A\3A\=A\HA\RA\]A\gA\rA\|A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A]$A]/A]9A]DA]NA]YA]cA]nA]xA]A]A]A]A]A]A]A]A]A]A]A]A^A^ A^A^ A^*bbAA)A3A>AHASA]AhArA}AAAAAAAAAAAAAAAA$A/A9ADANAYAcAnAxAAAAAAAAAAAAAA AA aaAAA)A4A>AHASA]AhArA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA A``A AAA)A4A>AIASA^AhAsA}A׈AגAםAקAײA׼AAAAAAAAAA%A/A:ADAOAYAdAnAyA؃A؎AؘAأAحAظAAAAAAAA ceA#33A#3=A#3HA#3RA#3]A#3gA#3rA#3|A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#4A#4A#4A#4$A#4.A#49A#4CA#4NA#4XA#4cA#4mA#4xA#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#5A#5 A#5A#5 A#5*A#55bdA#\)A#\3A#\>A#\HA#\SA#\]A#\hA#\rA#\|A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#]A#]A#]A#]$A#]/A#]9A#]DA#]NA#]YA#]cA#]nA#]xA#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#^A#^ A#^A#^ A#^*acA#A#)A#3A#>A#HA#SA#]A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#$A#/A#9A#DA#NA#YA#cA#nA#xA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# `bA#A#A#)A#4A#>A#IA#SA#^A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#_aA# A#A#A#)A#4A#>A#IA#SA#^A#hA#sA#}A#׈A#גA#םA#קA#ײA#׼A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#؃A#؎A#ؘA#أA#حA#ظA#A#A#A#A#A#A#A# bfA333A33=A33HA33RA33]A33gA33rA33|A33A33A33A33A33A33A33A33A33A33A33A33A34A34A34A34$A34.A349A34CA34NA34XA34cA34mA34xA34A34A34A34A34A34A34A34A34A34A34A34A35A35 A35A35 A35*A355aeA3\)A3\3A3\>A3\HA3\SA3\]A3\hA3\rA3\|A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3]A3]A3]A3]$A3]/A3]9A3]DA3]NA3]YA3]cA3]nA3]xA3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3^A3^ A3^A3^ A3^*`dA3A3)A33A3>A3HA3SA3]A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3$A3/A39A3DA3NA3YA3cA3nA3xA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 _cA3A3A3)A34A3>A3IA3SA3^A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3^bA3 A3A3A3)A34A3>A3IA3SA3^A3hA3sA3}A3׈A3גA3םA3קA3ײA3׼A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3؃A3؎A3ؘA3أA3حA3ظA3A3A3A3A3A3A3A3 agAC33AC3=AC3HAC3RAC3]AC3gAC3rAC3|AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC4AC4AC4AC4$AC4/AC49AC4DAC4NAC4YAC4cAC4nAC4xAC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC5AC5 AC5AC5 AC5*AC55`fAC\)AC\3AC\>AC\HAC\SAC\]AC\hAC\rAC\}AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC]AC]AC]AC]$AC]/AC]9AC]DAC]NAC]YAC]cAC]nAC]xAC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC^AC^ AC^AC^ AC^+_eACAC)AC3AC>ACHACSAC]AChACrAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC ^dACACAC)AC4AC>ACIACSAC^AChACsAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC AC]cAC ACACAC)AC4AC>ACIACSAC^AChACsAC}AC׈ACגACםACקACײAC׼ACACACACACACACACACAC%AC0AC:ACEACOACZACdACoACyAC؃AC؎ACؘACأACحACظACACACACACACACAC `hAS33AS3=AS3HAS3RAS3]AS3gAS3rAS3|AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS4AS4AS4AS4$AS4/AS49AS4DAS4NAS4YAS4cAS4nAS4xAS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS5AS5 AS5AS5 AS5*AS55_gAS\)AS\3AS\>AS\HAS\SAS\]AS\hAS\rAS\}AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS]AS]AS]AS]$AS]/AS]9AS]DAS]NAS]YAS]cAS]nAS]xAS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS^AS^ AS^AS^ AS^+^fASAS)AS3AS>ASHASSAS]AShASrAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS ]eASASAS)AS4AS>ASIASSAS^AShASsAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS AS\dAS ASASAS)AS4AS>ASIASSAS^AShASsAS}AS׈ASגASםASקASײAS׼ASASASASASASASASASAS%AS0AS:ASEASOASZASdASoASyAS؃AS؎ASؘASأASحASظASASASASASASASAS segyio-1.8.3/test-data/1xN.sgy0000664000372000037200000002412013407674361015516 0ustar travistravis@@@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  <Ŭ==u=)k=4m=> =If{=S=^_1BdBdBdBdBdBdBdBdBdBdBBBBBBBBBBCCCCCCCCCC?(?)>?) ?)7?)?)*0?)4?)?)?)I?)T!BdBdBdBdBdBdBdBdBdBdBBBBBBBBBBC)C)C)C)C)C)C)C)C)C)?Q?Q?R}?R ?Rv?R?R*o?R4?R?h?RIBdBdBd Bd Bd!Bd"Bd"Bd#Bd$Bd$BBB B!B!B"B#B#B$B%CQCRCRCRCRCRCRCRCRCR?zG?z?z@?{?{ 9?{?{ 1?{*?{5*?{?BdBdBdBdBdBdBdBdBdBdBBBBBBBBBBCzCzC{C{C{C{C{C{C{C{? ????? x?? p?*?5iBd =Bd >Bd ?Bd ?Bd @Bd @Bd ABd BBd BBd CB =B >B ?B ?B @B AB AB BB CB CCCCCCCCCCC??I??B??;? ?3? ?+,Bd Bd Bd Bd Bd Bd Bd Bd Bd Bd B B B B B B B B B B CCCCCCCCCCsegyio-1.8.3/test-data/f3-lsb.sgy0000664000372000037200000050230413407674361016143 0ustar travistravis@@Ù@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@㈉@@@@@@@@@@@@Ĥ@Ֆ@⅁@@@@@@@@@@@@㈉@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@zaaKKaaԁaՅֆ“Ö@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@KK@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@KK@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@KK@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@㈉@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@K@+okkt^ڞt^ڞok+) %*;I w p:O/'a  %1U_8k+bvA+olln^ڞn^ڞol+b[C|; " 'nl K*|zQH2]EO X( ]n~e"UKB+ommh^ڞh^ڞom+7 T4  1 +)h n=T-} \&[TKCq "4q 6C +onnb^ڞb^ڞon +i  w  [n rVV9 *&-aO^YOBY hsx/D!+ooo\^ڞ\^ڞoo!+SWT{G?% l~$ml0=xV: UD *_+`@ qC'8OG (QvE"+oppV^ڞV^ڞop"+-W! 6 !I k&4 #olc  (`Hg?0=![nYF#+oqqP^ڞP^ڞoq#+Oz`S]I :2: R0|0 PR%"  : qk!^v)g"G$+orrJ^ڞJ^ڞor$+]8]4TD} S0 , )cLo KI\cz d M" QH%+ossD^ڞD^ڞos%+3,< > : _Q # q]  VJR A er5MB uI&+ott=^ڞ=^ڞot&+p[  Jr 1 aiYC:K_4I  iBS0WJ'+ouu7^ڞ7^ڞou'+'nnY N``[sDI:L*J6v . !p -((ebzK(+ovv1^۞1^۞ov(+\f%M5 u]1 yP('9g6^z p" L)+oww+^ ۞+^ ۞ow)+^/ |) O 9  ZQ m W8hv nW NQ%/.M*+oxx%^۞%^۞ox*+%Bf~ W ZWmz"o`*`-Uu]X{ N++oyy^۞^۞oy++%,{gb.f \ b B ,E4 q^1 kEzT~OGNO,+ozz^!۞^!۞oz,+SqZY . QPUY6A@T4=r@ sw}+ z5@ i2P-+o{{^(۞^(۞o{-+ S V ~~ :iPy"K`$F 6t) /Q.+o|| ^/۞ ^/۞o|.+mL1ca@&? B 3 (SaM|WrOMpU# =rj\a0e @.pkkm^۞m^۞pk.; _hN xa` 7 Io&67KU5.{C jN3dg^A.pllg^۞g^۞pl.{<|_:N {J  Jn c1R" i 4B*U~"',1Y 5B.pmma^۞a^۞pm.9}p{> K {YvG: uu ! !C*YY AHC _2O  '(C.pnn[^۞[^۞pn.e  *K1OSD5 i -''G2 UZX$D?pD.pooU^۞U^۞po.=-`` Y4 j P RZ@&I?c0YE(N)Y  bXL-}ghQE.pppO^۞O^۞pp.H"  {`IN IF4%9m+oB L  00?F.pqqI^۞I^۞pq.  X^OOHobx]&p*B{27 bF G.prrC^۞C^۞pr.g62a | Iy K# Nj,//^ [0Q 2 H.pss=^۞=^۞ps.\M9 w ". 231V#,:;-8 U  R;wCH3h  I.ptt6^۞6^۞pt.#+5zN=jT ZReK[`bY >/zVzkQBJ.puu0^۞0^۞pu.^ w~ = m %!&  QK/o]w_;( $0 prXR`xK.pvv*^۞*^۞pv.) ?  kpJ zl]grP'57ha  ] ~U{ Hi L.pww$^ܞ$^ܞpw.z6g =;& 9*e<Y(Jg1K  hM.pxx^ ܞ^ ܞpx.~5T >p 4}!MF:)J  oQuf=N.pyy^ܞ^ܞpy.D j#_ V)  N$u?$G' I*5P G(6_yl iO.pzz^ܞ^ܞpz.LI7e+A!> sih*S` O+@Q};B5p@ ;] !#h a <P.p{{ ^"ܞ ^"ܞp{.? H % Y ^"Q8|8{8=/ ,]O@U dQ.p||^)ܞ^)ܞp|.zE)\\d Yh j { h&UiB~sH"NO!% v=;2 -@2qkkf^ܞf^ܞqk2._T2H) #B?K_9 bXN ' u fLsA2qll`^ܞ`^ܞql2Wzz< G7i#;N$ #`}8C9S;"PK (/P}~i B2qmmZ^ܞZ^ܞqm2U9u5. T E } Nu6  NV% }`c<^1BgZC2qnnT^ܞT^ܞqn2i1. V  |  J   JH{n; 6 B yW='C, jD2qooN^ܞN^ܞqo2_V/AUNy x-a #Wp@D  AsE Yv .ew# ) E2qppH^ܞH^ܞqp2GrO I*"g  Q(~wG7]|t8 3F2qqqB^ܞB^ܞqq2'Y E qg8 D~ I\22L jI::}>$Ghm -G2qrr<^ܞ<^ܞqr2<^!8 B q hR"I >6ihk d  17DmHH2qss6^ܞ6^ܞqs27dt ( z  A Y V<|@i9z ^G nKI2qtt0^ܞ0^ܞqt29 q<O WF F j>A 4Ih F_3!86 iM>o mt J2quu)^ܞ)^ܞqu2,Np np} ;$guHf G 80n ! + K2qvv#^ܞ#^ܞqv2A+  eN^ a^] L:s B5k 9|LVRbt$K Ih]L2qww^ݞ^ݞqw2tsX9H 4!S ~[m "";w+FJGDMRnoBA} zV p-dM2qxx^ݞ^ݞqx2 !BK$ l< 6 Zc}or5OPhH> o[9 N2qyy^ݞ^ݞqy2#|0 _ ? M) *{Y+@/J J 8]6Y>}O2qzz ^ݞ ^ݞqz2)z~f+=r t  J }wP;>x+{y{"k4 ` K?[~ =P2q{{^ݞ^ݞq{2Ud2Ee x  Z C[hrY %ax`{vi'J72z h>j!}  T1x@ Q2q||^#ݞ^#ݞq|2Fm' `]jO> 0fKY D' w1- ql+b&-^ok@B6rkk_^ݞ_^ݞrkB6EW 9  } ^v'  b E x.-]D7;f|z^59z%AC6rllY^ݞY^ݞrlC6"dU , _ xN ( L' _'O;ZdPV BD6rmmS^ݞS^ݞrmD6_.+9m 3Z {  T!w[t GqV8Z Q Ww? ` 2IX;"o% w hS94wCE6rnnM^ݞM^ݞrnE6Jn>{e gn Y IH - Tg B&MV7 .wDF6rooG^ݞG^ݞroF6=B_k;D" 9^mf~EE|Y ?V["Zz6'd\FEG6rppA^ݞA^ݞrpG6@mQ8un`S 9 4 &^4;0MGD i 1g 3 d ]FH6rqq;^ݞ;^ݞrqH6}oc+! !EXU dOHXg: A;P.]_ =} Y1 iGI6rrr5^ݞ5^ݞrrI68s    C| m y V+^ ;6UBE;UTk.L X N sHJ6rss/^ݞ/^ݞrsJ6cdo m n F 7 { kq%>  7bi MlIK6rtt)^ݞ)^ݞrtK6 ~rw7 - r | s}3* ssZp e JL6ruu"^ݞ"^ݞruL6?:2. 2    t  {K rAj NV. ixzv[aDhKM6rvv^ݞ^ݞrvM6en R{  , ] =J|1jt"gz#fEdc  fK].LN6rww^ݞ^ݞrwN6V h Hr@ ) NP6ryy ^ޞ ^ޞryP6jN9#w i [ m vv ~/"<1(6R   1 OQ6rzz^ޞ^ޞrzQ6(Tc_ F|7!0 hjIC},V  OD673-W 6 ! PR6r{{^ޞ^ޞr{R6Zqk3dE D 9 5%HpL S ) Kr`WU<"bO&]1aSQS6r||^ޞ^ޞr|S6hmg3i , #=P 2!SKJFS!fwl 7 wx c 2z8A@9skkX^ޞX^ޞsk9vh1,e y S j ) <&jf_vep)aP ,t_A9sllR^ޞR^ޞsl9F4P'E-(_ l = o b N &k@R`  gVm%y(KmB9smmL^ޞL^ޞsm9YXD(54 +6( I H;R IO7 H\6U`*E;sYm C9snnF^ޞF^ޞsn9lw  " , H j 9\n[ $~mQ@= ^U G4   #DND9soo@^ޞ@^ޞso9^taVc 4y t ~ Yh! 8S(kJ}%sBp$< # ].E9spp:^ޞ:^ޞsp9>%R k  ` @ u P 5~Q"Z<Z;T V xS s[O& F9sqq4^ޞ4^ޞsq9sk+n q _ /5_@Sq ! F6F)=M 5( iS Y  G:srr.^ޞ.^ޞsr:1 ~D1 ^2;. -Y [q 4x 0 P "9 a[<L H:sss(^ޞ(^ޞss:vGE/C q?KyY{ 8Vb1P|243 x$ #C ?Z y.Tl I:stt"^ޞ"^ޞst:0c&A *}DB: D9IN=jb_~m rUT ,K J:suu^ޞ^ޞsu:EN|)g w H~ >f GpvGr5fdP a?aN$ pLRxK:svv^ޞ^ޞsv:((4l5,: O  Qa>{YPM)~R|~nzt4  v. tL:sww^ޞ^ޞsw:p2I\TE .)" Mdo +DNc822xP W 7.Dp O\M:sxx ^ޞ ^ޞsx:~q G[nI  KGK * 3_ !, cL-zN:syy^ߞ^ߞsy:* g8c _40^ 4 f >hDJ P|GRtEc.0O:szz^ ߞ^ ߞsz:8Z7  A:N] lOBTdzD D%"u?D!Kh )pSP :s{{^ߞ^ߞs{ :| 7 V r d  8?Baa^P6e" P-(n Q :s||^ߞ^ߞs| :sh A K x% 4b 7M[5$I%h+ w U;Z@=tkkQ^ߞQ^ߞtk=#]D  v 5}cBEGTAGU6f5/ 'Q wux NN=t6f A=tllK^ߞK^ߞtl=3A8j5  <  )2*rp  p{r k$(@B=tmmE^ߞE^ߞtm=O/ yHSIIr .\xC  I34l >iL9vC=tnn?^ߞ?^ߞtn=5$l I y P| 4fg ud{ /& k_n;, D=too9^ߞ9^ߞto=wV 5 j=lGEIZ\L0 00rE=tpp3^ߞ3^ߞtp=ctu0 nQ S5ye 5kNz e sHuyq~ Z U Uk<F=tqq-^ߞ-^ߞtq=MJ~T m-1 ne21 Y'0\ l IK "L xG=trr'^ߞ'^ߞtr=@MppTR 1"I # >1u P4<;LlMb p H=tss!^ߞ!^ߞts=?N I (-.L."? c Qm*Z RC 7 nP&I=ttt^ߞ^ߞtt=Wo}%!97 @vs ,dL .[F ) 8D3h J=tuu^ߞ^ߞtu=)K>f vkRvUv~ZYt~ '{BPm|^;K=tvv^ߞ^ߞtv=l5&ML BQ [`o! lWjD [6Sr T L=tww^ߞ^ߞtw=`r)bap 4Y  h jdr<Mv`qA #vk6M N JOSM=txx^ߞ^ߞtx=Kzdl?\ %Ah.Ke + A:?ik:uf*>6e~SjN=tyy^ߞ^ߞty= "~r ! @ 0'F?e ;'6uW? Uw 3 >bd) O=tzz^^tz=Cl#k 9O ^ (M^@ ;]907u/ry$FE[s: P=t{{^ ^ t{=t<W  no pleM2LoC*J Mv) k4Q=t||^^t|=N4I 'v{F ran8z,pY D },@gAukkJ^J^ukgAth1l<Ir  @=qhGnJ`lI:  \ t%TtAhAullD^D^ulhAg * S )mq= y}flBiAumm>^>^umiA fC\+N | a  ! =/-M6 H'Aa~ x[bQoG1dQ CjAunn8^8^unjA_g~/*} W 87191[Fhpos |B rS 2l@ -/9DkAuoo2^2^uokAPZ  jL7'f+# WYs2c Bsa VAF:b OlaElAupp,^,^uplA,2waOI |4% v}L"9  =)iVCz^cO0 FmAuqq&^&^uqmAb*bXEUo)vq (<e^4 C eta&DH,q%GnAurr ^ ^urnAY = !~H$h F .-5+9<[FHoAuss^^usoA= I*> 1j:v =3Oy3 s9 ?EUAN3|x IpAutt^^utpA / R=+w?oeo J; #  SQ5  H JqAuuu ^ ^uuqA]OkG2 |%R{ NX.K~ KA x E[KrAuvv^^uvrAV2- 2 ' X H9H tdj*"  I   z~Zdco t LsAuww^^uwsAuI%3c 9 {_K B[5X-jY418U 3  95  MtAuxx^^uxtA~BYH, % [Xn G@ :uVSYRsV'9 + klh "nNuAuyy^^uyuAY` ' ;c u  z(eZp{-PF j4d dZ "q(OvAuzz^^uzvAz>* ]A l27 ?h/f3VeBmt4@%AEvll=^=^vlE\He P WZ %S($I5DU h@S` _ N-h' .B Evmm7^7^vm E>gfZ d xK { ]lh+zGGb^j6 Q"C}P tP C!Evnn1^1^vn!EiA IG? V  `Z y?. uWP("slULi D"Evoo+^+^vo"EP.G. a%EzD 4 0I oS9{}Ep5  J /E#Evpp%^%^vp#EH9[Mg  R # z0Q  1 X$h  ;lq Uf F$Evqq^^vq$E/ilN}JF NwjUnj5L9) ?_ M| H. dRb6 @G%Evrr^^vr%EN'-:  QEX*0 ؆O 5 B >Su CYxZgiHIH&Evss^^vs&En#V K Z / `D-F(.=e{ , ~KI'Evtt ^ ^vt'EuPh   Z A64nB_nW(X|;i_ QzP# J(Evuu^^vu(E?)D y 6"h zay4*E{C^~  w& .H^pRU uK)Evvv^^vv)EkZY-CSu?  pB zA *H]Bnm 0\%Z49z  1L*Evww^^vw*Et:g  k!)f \2 zN 4-) lI M+Evxx^^vx+EEK .!`wR Wl$3SW-Cnt (f]p8 _N,Evyy^^vy,E*= c-~ fT.sB*k- "{  c~O-Evzz^^vz-EGAIJ! mm,3: p:I~  0{yAGP.Ev{{^^v{.E2~  4&1Bf .j5B`= n( a 6i* 5 Q/Ev||ܲ^ܲ^v|/Ehs  It4 -lko x+W Fhg (  K k :b@Hwkk=^=^wkH_ #TF o#q%q._ l 9 )4jV@l1 PAHwll6^6^wlH\-L?x&VP  - hD! F>AX*K 8`m SO z(BHwmm0^0^wmH`oZZ faR 4 W -Y|EzXU fX!E q  >CHwnn*^*^wnH c R  7 1073 $ \-< >( 'H]!6 1Ot GA R DHwoo$^$^woHX4vgcwV   vP[nQZA"a49KAM1tQD EHwpp^^wpHM9%Y53d|8  I EQaAj / F olLR s~FHwqq^^wqHR_];%v d`h^  B_?HB G {a<[KByR4(!Zy b GHwrr^^wrH?Js Q 4 ] 4h &3Xd lG&fyg3b= ]aDY>SHHwss ^ ^wsH" 06B)gM- b D M X kc) q9'6e=woIHwtt^^wtH&K'a,/ ' Dt#}_atO/az G [6I<JHwuu^^wuH)w t  G p t w[j M" 5B.sa-?8KHwvv^^wvHA3w F S ~w)6ZTzy2a +_>wK S[LHwww^^wwHGt>M sYG $ T~nE #Z\ M@ 'rMHwxx^^wxHWXZ@  t  ORmgg0 _2 " 7!= S D uNHwyy^^wyHn UJ'nPjT&o-MJ"1 8=[Jo bOHwzz^^wzH@WDR u\ / * !A# sCh* 7lXJ[pCPHw{{۱^۱^w{HA] G g 5l9 )(aG;t)c37]KR T0(QHw||ղ^ղ^w|Hmj"y * 3 cfpQ}; (t x; d(wE 6zDe(hs>@Lxkk6^6^xkL1SFtSqG  4j h%TM A %U< '9:OHALxll/^/^xlL@9Jw U gX[748I;OD%`|]yeF) {VeuBLxmm)^)^xmLi6 ^nr-  MN;-9h i %N] [_TCLxnn#^#^xnLtL1+  .{ \ Kb[ we }MPC u,rS 4} DLxoo^^xoL#F1n ?^ ]{O< d B5 # OV m-_  x~ELxpp^^xpLZb IY cxI?db/1 / mBb e6x2.RCFLxqq^^xqLd|93  q w- Qu HSW%79 )ytf Dra GLxrr ^ ^xrL }4% uB!xRJ e p=( i .yC 15HLxss^^xsLa3A ) j]@>}cQW |<d ,1l b7 ,fILxtt^^xtLYH4 T r,KZ W* `{>Es H!>O y&i; 2JLxuu^^xuL*-(W rj x  ( Q K-utYk=? Sv ;& e3 b}KLxvv^^xvLcD-;:Jd F ?)P X[:Mv5N)  gLLxww^^xwL@bTU3| % q; &]%'>:OLxzzڰ^ڰ^xzL1~K |P3 L'w#"F[M ^( +`- NH=  a ^PLx{{Ա^Ա^x{L9Zh| n- ^  i?&"wZqK<:u l < 3 (  cQLx||β^β^x|L[b (Z{  A yqpb\'4 7S~ p@CPykk/^|/^|ykCPuY{ou `KGrBa+hg&1 A/)3:3eUs ^4}ADPyll(^(^ylDP 1u?~r@ A)"aW e RI*Q^ (:BEPymm"^"^ymEPWzj\`v`& Nw  B#0QKSZ2u H) ~Xk ?ECFPynn^^ynFP<{yY ) }~ccv"uJ.M [eW: U-P/e hDGPyoo^^yoGP<nl.>C MlKJC5s"0=T)uQ(?EHPypp^^ypHPD3y)q  "'uZt }eU_Uj0y-wB6 E;+X FIPyqq ^ ^yqIPQat  I {D  X%t"a  +([#+!fN  GYGJPyrr^^yrJP % x  SF\[ u  RZ `HKPyss^^ysKPqoF'%y 66  M (%.Gj* &pIi ~rILPytt^^ytLP&R@XOuQ \ d #2 4L= /)AV I Pj! 3 ) vJMPyuu^^yuMPG@ " 9U K vK`PF fVZ%& ASbKNPyvv^^yvNP~b@  - C 5+~&8dUD _Nvp='zLOPyww^^ywOPE\ ^O!/tg ) 4 l"{ > 0 wOB`MPPyxx߮^߮^yxPPXX &H =^ 6K}S1p#k%3Ky p e, :NQPyyyٯ^ٯ^yyQPwBNT_<7 )5yQ Q%t :DpWd 9BK AD ORPyzzӰ^Ӱ^yzRP(f ;  Sk{ -8S75I~ 1 DPSPy{{ͱ^ͱ^y{SPnCF#  u tnD] 6Ci P11KBQTPy||Dz^Dz^y|TP ?Bo_  = CR tokuKU -R  o^ bv@Szkk(^v(^vzkS_5Heb &'[ lZ mqBn2~[4VvK9s ASzll!^}!^}zlSy[ o9_T6 >2 / S  ytL\or lbBSzmm^^zmS]p 9  %xU/h@9VOu iqw6 `NP CSznn^^znS%0yo%x 4r n`4EbNRsJ _+ RDSzoo^^zoSsTHiEPhzn6P s 3 x &#BneL(W obqf`jcr ESzpp ^ ^zpSrA 4,!FC-< -?  d>; FTzqq^^zqTQ.B%G   +^v | !N`=e]u GTzrr^^zrT_q*in _P cgY ObF^K  U{v*/|#. gTHTzss^^zsTB$ 2)[+v>Y[>  X${ &KM &kS 2>ITztt^^ztT{=2 + F KD )H*r KR_^[S +JF_+ FcPE55JTzuu^^zuTN Xc7*j) Qc8*mmE K,,k> bKTzvv^^zvT 1 3 &? I o$u _]%W vZ6Nk/LTzwwޭ^ޭ^zwT<%h&A %@  9y Qe [R$>f$MTzxxخ^خ^zxTpX,\ , $ )H]ew dw O0h  w IoU NTzyyү^ү^zyT 0%a ,BxXY j~P 1?(O Tzzz̰^̰^zz TGRBB~a aL   $Lj$=#Pv urJzG[ w  P Tz{{Ʊ^Ʊ^z{ T !L f\Bv d  O/ KO 47n I"Q Tz||^^z| T9c e ^ /V G 1'T ?!*`RC } j1W d<@W{kk!^o!^o{kW !J7 oN! 4gYAtQ=F cCr{XAW{ll^v^v{lW nlE]] kg5|EQV?$j Rd _;b ^}BW{mm^}^}{mW /X\  ^ dAD 40K,9>aZ !z RpA>M  CW{nn^^{nW]~3v Q IY~@!(Ph4iG"$y O m~'_DW{oo^^{oWULA`E.4i )7MS="`F"6@  Sv e x52EW{pp^^{pW)TA  z %<n 9 XR ONV\. pSV 3  \vC & 4wFW{qq^^{qW*g Qr 9} #0q| TEGC5  nGW{rr^^{rWH3I /Ez>-Tsn >aUy:O O)R 3=J 7HW{ss^^{sW"8"{ / ?-uBH dBVB IW{tt^^{tWE"=899;.U xY 5IBy<= ! l D+ }FA>(r+ JW{uu^^{uWSQq{aw & p gZ # i Q:;8% % e( + 7wKW{vvެ^ެ^{vW2h;CZ1 g Hm9 8ct4JHL Od D`YX\ 0LW{ww׭^׭^{wWa H KGWY gpj,R nv @< ^ z~ : MW{xxѮ^Ѯ^{xWt I[ Z t ]@*S: UKrs  g 7$] i1A3aQNW{yy˯^˯^{yW)30~+X# Z( au.nk' @R d0%w  D%/ OW{zzŰ^Ű^{zWa |% JZ! ]Z U-jyQo `= v7qh PW{{{^^{{Wt"zX 1 y_ q^ ~vv_i?C n"`lK) yr pQW{||^^{|Wpe6} % rM ?E z-c\$z/0^)Nj  kd/[W@h[|kk^i^i|kh[H#) !jU )or Nmmcm l &Rj (IgAi[|ll^p^p|li[LBx o ag]WNfhOO6 j A E  wx" u +~HJBj[|mm ^w ^w|mj[ ^zR_ AFyKG^e w I"d {-~ Ck[|nn^~^~|nk[ '  s#"S7KN >h }lExX |Dl[|oo^^|ol[n L  ,! KKW6-!65 `5 wo1 qEm[|pp^^|pm["n   ! TQXH^5.$dU,:Fn[|qq^^|qn[<A r} OG{V^ A6\W \,- 2L !  Go[|rr^^|ro[aKY1l ! YuH 5MQDD Fx< s$ 3]::gHp[|ss^^|sp[* ubm Wf&@f}GA^:`C#-B F u JYR Iq[|tt^^|tq[eIgf >5,Ma- 9N  z=H: 2E5EkW}6 Jr[|uuݫ^ݫ^|ur[}yqPL  #LLL * (:Z%9g E!+ EV Ks[|vv׬^׬^|vs[ L,  Usx>8Zz<? [Lt[|wwЭ^Э^|wt[1"Kl - NHC _1 RL8KfF \O aRP4 {L wg  Mu[|xxʮ^ʮ^|xu[g02 ] &;  vra>D7tGpc f:_-LC  Nv[|yyį^į^|yv[qU)b^P_yGa4 -4 ^d M>dyZOw[|zz^^|zw[i Pf zQ2 wj13Em?1c#It  A _}ll ^j ^j}l _`Dczl GGu"(R[7 mP )bB!_}mm^q^q}m!_t hJq G " ` #4 YO j:>K  C"_}nn^x^x}n"_Zrd,  iR F _hY _j* 0rJ2UUG [ ]^ !\%N/ D#_}oo^^}o#_." ON5  *f5F((9"Lpp% E$_}pp^^}p$_ N [@VrRjn ,u %` s6c?+`W fF%_}qq^^}q%_Qn8s  qJ Mgw s-Z6B \B88?mW A2vU|7G&_}rr^^}r&_e={G L E | 5j51<' | @ bj jH'_}ss^^}s'_<$'XG Qyi +> roo]Pu\Fk+ ?\@ >~ O" I(_}ttܪ^ܪ^}t(_#* x  BJJ q "u L) pV)@7 96Ur6~J)_}uu֫^֫^}u)_z:N Z']hi > wVA !\r~k6?OYTK*_}vvЬ^Ь^}v*_ ez0$W\AX iVSW0T%a gM1L+_}wwɭ^ɭ^}w+_8n Cm , S 6o=tN :1x5sK/F _lN-_}yy^^}y-_6]Ojej s@wQ8:R:y'_ @WQxc cvG'~ cZ$O._}zz^^}z._5m=6K 4=FS"j /MCRi.h@N rb Zs">B5 P/_}{{^^}{/_TCo Ch ' t fR@b~kk ^] ^]~kb' Y JXQrP oEq P9F!|2 "_NJ Ab~ll^d^d~lb||tB4 LT`3] XE Vf  LX q okBb~mm^k^k~mbyli*iM H n~IwZp_  pP _^ e { 0,O Db~oo^y^y~obRU_z \)t U{ f[Y 9UK]ZjBbug z&QpEb~pp^^~pbHoHKT g!. ; uab?&&$6Gn?  Mg;Fb~qq^^~qb B  > iA< '^uLb 5t/ODgqUJ. 1Gb~rr^^~rbFVO k '  | U:GqAFrhDKpiPn 4_Hb~ss۩^۩^~sbN* 2 \ 8khO k X).Jc NqtEiK6 l Ib~ttժ^ժ^~tb#K!  @$ 2\ f U I +AA P  b! h _Jb~uuϫ^ϫ^~ubt - | `r$&B ~[ ?/b 1_?v. ]/Yg@fkk^W^Wkfyd[ 7 { A>[{ S m;; Zn1V*`Afll^^^^lf*&B| K: r fOtS k PqfZ \Bfmm^e^emfL3[SmA Q=t   f=]z' qCfnn^l^lnf .{ gx\  9* f g f 8 <0cxrP n2qO ;pDfoo^s^sofLQu6S-<JA5i C /-!,YMLN3$<NEfpp^z^zpf=q3I 0 DH ZHL$T] @ b g_ < e)OFfqq^^qf(/-MIW ; P + ; xD]d)e/ N{lXGfrrڨ^ڨ^rfe]d),hR t(&n W ,;W|| Aw,bE[!N 2_ Hfssԩ^ԩ^sf7 0] ]]9)K  v) 49<n4tN  >Rnt$*%dIfttΪ^Ϊ^tfr 9Q6  ) / Gn1 z  tzRJ&-y(( - Jfuuȫ^ȫ^uf?e#G c AA PZ  A '-lU_A nKh$ =Kfvv¬^¬^vfA @7ui (v7 Fmo# ! [V 9h P KvWLfww^^wf6@,d , o7:!}X9D{@B~b IF!C Mfxx^^xf6d^oT @  ? K ]$~Sl \1\E j9ygteKNfyy^^yfmfe/ 9 [  a S 8D%3[qex\Ofzz^^zf>FP '%lnyE'7e 5+Q c UbS  \4Tm3nPf{{^^{f&]e6 93( 7Ghu{(Zm8 qQ4T \ xapQf||^^|fJo+[r%ZQs. {0&T n gLHfvS L8JI>]m@Djkk^Q^QkDj%CF>^ Ba n ]SQ}= vNcFLdB,2h7 < )Q`KFJjqq٧^{٧^{qJjLw:c5/"i * ? M x`">%Bd:C'_Hba"FV^b GKjrrӨ^Ө^rKj h _ 5VDKp A ;pg r6HLjssͩ^ͩ^sLj1[j 9 o( ZQ gvyS "u#h} IMjttǪ^Ǫ^tMjKJ7:8  J Yc g ]uWMm X $LXAeep HryJNjuu^^uNj& MMv {z?iSte*{['KOjvv^^vOj i}: ^ Y O J 9FF a! 9oZ +{\3.KLPjww^^wPj VTa[& w *+ j 1EMC oiW" 1t-Yw~a@MQjxx^^xQj 8Ip]>) u +9n  (J5 O l{97 (at<NRjyy^^yRj[22W : W  v):h7,X Mt<R!n:| *Bi~OSjzz^^zSjl{{Z  oR ] H Q }ur.3  u'Sb4rPTj{{^^{Tj$\ mg!Nc ?3\ 9O;(]Q9QcUBS G'QUj||^^|UjvU, F E e `S~~prrxx 1Yx8 Iaz@mkk^K^Kkm} w\R  m s W ._qk 1  p UE {rBAmll^R^Rlm^:D ~PS  _/~71 ~w2H8'wy!#" Fd * \Bmmm^Y^YmmC"u 7Cl )aPK_ 54!<A0$0mtR NOL Cmnn^`^`nm7t7c c  .  ? OD tm99 2fDmooޥ^gޥ^gom&g,HGshzoR bRGfPu +[jb LjFEnppئ^nئ^npnB VBW z)p zv ]?Pju w&Lm&T jFnqqҧ^uҧ^uqnWdW9 ,P81 |,Wyxx{j dX& ZhGnrr̨^|̨^|rn|2%"H -_Vy0A'b$ 5bII;&K!(X ic$,XDyC@mHnssƩ^Ʃ^sntTtOn t  m M"  x {|\Hf*IRbKn#g2 mDXMVh) ; Intt^^tn()PS( a36'cj Mi3 ,WR K?xi?p 3G:A]#[`Jnuu^^unt vN'hV&}t d,Ss  X2 t[? HWzKnvv^^vn* +4U7 :tMr K _n})T KA@  : n^$4?OD0aLnww^^wngzi[? Aj ) 1F<{|y 7hlRU 43\*9_90Mnxx^^xn9 _{ {$ !&9s h Q\v 5 +znm] Hf4WsN nyy^^y n=JaQ2 !$Dh2( 7- P,7@ ? S7.O nzz^^z nYHV#>PZbhKr#1AXzBY@^| Bqmm^S^Smq ILA[2 4 "= ` fOwQS @'EK1 e!T-TM 7$lv\Cqnnݤ^Zݤ^ZnqMMwO/ }#K TsIc ? K{# h4w[ 2 QxDqooץ^aץ^aoq--dm|%|sr i{" j;> hB"Rhno0 yRlEqppѦ^hѦ^hpq=.^a S A[fd a (WI6 99L& j3_2 MO\ +r 0Q/dFqqq˧^o˧^oqq^ fOY Is = +~j uLxTm2 hXieS GqrrŨ^vŨ^vrq9D0*G# @u#}_8 gL +j5 |%|Hqss^}^}sq|1, M  < G6T < <';^<4 n8lEd&3 gIqtt^^tq}% CdB>+g sg>F +h4> 0D&IP\Jquu^^uqu%16}Te K f#X 3? z]e Pt Kqvv^^vq| A$G  N+D^m pf Cs~ih9V7V7v0 >Lqww^^wqviMTjd0f9B ~v Q0VX 3PR 0Mqxx^^xqEouLrii&0 \CL}@ 3`tpIRL =g0 Vy Cc`j YNqyy^^yqrBV . ZWw-u fX[D xKE}C C F w=Oqzz^^zq+G!iW :  AY  4tB 7;o 1\ #U+ X,Pq{{^^{q+U7`r  v:gtbA Z9 d} 7) (X J Qq||^^|qgyKah_ o O _K;T<+XQ kR@CF `@iukk^?^?kiuo 8A CJ b/ \;kL^ Hdk M 3s$Ajull^F^FljuL  yT#(;( K$$z& xBkummݣ^Mݣ^MmkuXtSNC l E1aO%QaV t-  k53KF 9@MClunn֤^T֤^TnluejS h ; p glx |AnN4g#Gw} q;]FW?DmuooХ^[Х^[omu~i\-;{> }i yEnuppʦ^bʦ^bpnu;tZ'h;dZ 9 &noq! _iM]w .;W>|Lx f.~ Fouqqħ^iħ^iqou @sO"   z}W~ 3V Prh2b @+P k p7!sGpurr^o^orpuK9W> O:79XW$HdW2xR* K Hquss^v^vsquR9   \R=C  gj# _ 7q5w]HX Irutt^}^}truGB-` f x(wcX:CCJ#  /FDRnKlJsuuu^^usui]QlG& 7 lO'Iy  G(7z l ; 33$IQ HD@Ktuvv^^vtu&3  x QS  LB. %w]9gi b.s 7 S&Un-  Luuww^^wuuc) v eH= d "`7Lt  {R Ku*~Pl ~k ;Mvuxx^^xvu+4 P@O=w vy B=- ~mzl7GXZnNwuyy^^ywu&ollr Ag  8! CR&G kN jG~uN2Oxuzz^^zxuQ >  kP 9 f> kXm[_( wlPPyu{{^^{yu<2 2 } sK` A. : Pd B@Qzu||^^|zu6_I 5 cm nT 4 ~ ,LfRD0 w o ; a5]@ ykk^8^8k yYpM  r  : 6[Jvhy% c  _@*k EtA!yllܢ^?ܢ^?l!yf!s USPUzM) }{FWRE9,]j-  R-$ h  B"ymm֣^F֣^Fm"yt;w :! s\SoPcdhNFp(h(or5  fZ,_C#ynnϤ^MϤ^Mn#yZg !    Jf wdB(> !X ( 9 ,h0 {4^jD$yooɥ^Tɥ^To$y219Lg\oa K = 7E%yppæ^[æ^[p%y'P1vY  E}) 8n,i1NsH` yM +FZ- )W]-F&yqq^b^bq&ybB 4   @` v| &t5 R _0!} ;& X y:Q G'yrr^i^ir'yoe4&%Jp C " QsHdy Ww o50, m[<H(yss^p^ps(yGD/z j &K F Ic  rP $0 5./Y2  I)ytt^w^wt)y&s(yc)j sE ( ,$Sp}:i H VU %U q >>~2sDjY_  LE 4 jzJ L,yww^^w,yD=6j<) <]qR %YF 59O0e l~)1 fM-yxx^^x-yz]1*0'YF 0p_KG>]= # ?=f g !M N.yyy^^y.y%zp mjUn~ ;vX  ZZ  Mh >D 8O/yzz^^z/yCU;|&. =5R ^q!u ) . I{ \aOo RP0y{{^^{0yQ <"gbN_4aS: m@e( P ZD^}>Q1y||z^z^|1y&7  j! _vwA~ O h Y! CW9 @|kkۡ^2ۡ^2k|2G ]  99 4Bj Gc HGxvXI(' r 5A|llբ^9բ^9l|omqS{N NJa X& O 9 LYd v[4 !d81nj2B|mmϣ^@ϣ^@m|z ` _@ G U', mw{wW [AM :M}C|nnȤ^GȤ^Gn|jxo k| XrQ<7+%CL+9 ;9 :D|oo¥^N¥^No|8|   1#L< }N h0p 5ko6% ] $ E|pp^U^Up|O v1 e;I ! Q6%n"; ^jb F|qq^\^\q|< ,pfz  Zp2AMfP7iR # P3 1 ]rWvajwG|rr^c^cr|Q$tM{~'r z Zq SO /l   `PQ3 a NH'M;BH|ss^j^js|  cB J r,x q  :  \wp vI|tt^q^qt|aK [ Znq" @ */a !I=G 5Ln M|xx^^x|U8QCTy $Z^' srjV5 Ic\ .zy lad I QN|yy^^y|a{k hD [9 } 6:M Bk0By (f O|zz^^z|Ho<, `NI)hf KNdQmO Ct,9j''P|{{y^y^{|G}* j}I$ W 4 cYAdzx!Q|||s^s^||[oK0G' j 0YJke vzu9]# FR $segyio-1.8.3/test-data/1x1.sgy0000664000372000037200000001116013407674361015461 0ustar travistravis@@@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  <Ŭ==u=)k=4m=> =If{=S=^_1BdBdBdBdBdBdBdBdBdBdBBBBBBBBBBCCCCCCCCCCsegyio-1.8.3/test-data/small.sgy0000664000372000037200000003441013407674361016163 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2A33A3=A3HA3RA3]A3gA3rA3|A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A4$A4.A49A4CA4NA4XA4cA4mA4xA4A4A4A4A4A4A4A4A4A4A4A4A5A5 A5A5 A5*A55A\)A\3A\=A\HA\RA\]A\gA\rA\|A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A]$A]/A]9A]DA]NA]YA]cA]nA]xA]A]A]A]A]A]A]A]A]A]A]A]A^A^ A^A^ A^*AA)A3A>AHASA]AhArA}AAAAAAAAAAAAAAAA$A/A9ADANAYAcAnAxAAAAAAAAAAAAAA AA AAA)A4A>AHASA]AhArA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA AA AAA)A4A>AIASA^AhAsA}A׈AגAםAקAײA׼AAAAAAAAAA%A/A:ADAOAYAdAnAyA؃A؎AؘAأAحAظAAAAAAAA A#33A#3=A#3HA#3RA#3]A#3gA#3rA#3|A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#4A#4A#4A#4$A#4.A#49A#4CA#4NA#4XA#4cA#4mA#4xA#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#5A#5 A#5A#5 A#5*A#55A#\)A#\3A#\>A#\HA#\SA#\]A#\hA#\rA#\|A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#]A#]A#]A#]$A#]/A#]9A#]DA#]NA#]YA#]cA#]nA#]xA#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#^A#^ A#^A#^ A#^*A#A#)A#3A#>A#HA#SA#]A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#$A#/A#9A#DA#NA#YA#cA#nA#xA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# A#A#A#)A#4A#>A#IA#SA#^A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# A#A#A#)A#4A#>A#IA#SA#^A#hA#sA#}A#׈A#גA#םA#קA#ײA#׼A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#؃A#؎A#ؘA#أA#حA#ظA#A#A#A#A#A#A#A# A333A33=A33HA33RA33]A33gA33rA33|A33A33A33A33A33A33A33A33A33A33A33A33A34A34A34A34$A34.A349A34CA34NA34XA34cA34mA34xA34A34A34A34A34A34A34A34A34A34A34A34A35A35 A35A35 A35*A355A3\)A3\3A3\>A3\HA3\SA3\]A3\hA3\rA3\|A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3]A3]A3]A3]$A3]/A3]9A3]DA3]NA3]YA3]cA3]nA3]xA3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3^A3^ A3^A3^ A3^*A3A3)A33A3>A3HA3SA3]A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3$A3/A39A3DA3NA3YA3cA3nA3xA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 A3A3A3)A34A3>A3IA3SA3^A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 A3A3A3)A34A3>A3IA3SA3^A3hA3sA3}A3׈A3גA3םA3קA3ײA3׼A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3؃A3؎A3ؘA3أA3حA3ظA3A3A3A3A3A3A3A3 AC33AC3=AC3HAC3RAC3]AC3gAC3rAC3|AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC4AC4AC4AC4$AC4/AC49AC4DAC4NAC4YAC4cAC4nAC4xAC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC5AC5 AC5AC5 AC5*AC55AC\)AC\3AC\>AC\HAC\SAC\]AC\hAC\rAC\}AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC]AC]AC]AC]$AC]/AC]9AC]DAC]NAC]YAC]cAC]nAC]xAC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC^AC^ AC^AC^ AC^+ACAC)AC3AC>ACHACSAC]AChACrAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC ACACAC)AC4AC>ACIACSAC^AChACsAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC ACACAC)AC4AC>ACIACSAC^AChACsAC}AC׈ACגACםACקACײAC׼ACACACACACACACACACAC%AC0AC:ACEACOACZACdACoACyAC؃AC؎ACؘACأACحACظACACACACACACACAC AS33AS3=AS3HAS3RAS3]AS3gAS3rAS3|AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS4AS4AS4AS4$AS4/AS49AS4DAS4NAS4YAS4cAS4nAS4xAS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS5AS5 AS5AS5 AS5*AS55AS\)AS\3AS\>AS\HAS\SAS\]AS\hAS\rAS\}AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS]AS]AS]AS]$AS]/AS]9AS]DAS]NAS]YAS]cAS]nAS]xAS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS^AS^ AS^AS^ AS^+ASAS)AS3AS>ASHASSAS]AShASrAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS ASASAS)AS4AS>ASIASSAS^AShASsAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS ASASAS)AS4AS>ASIASSAS^AShASsAS}AS׈ASגASםASקASײAS׼ASASASASASASASASASAS%AS0AS:ASEASOASZASdASoASyAS؃AS؎ASؘASأASحASظASASASASASASASAS segyio-1.8.3/test-data/small-ps-dec-xl-off-inc-il.sgy0000664000372000037200000002412013407674361021673 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  BhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBhBhBh Bh Bh!Bh"Bh"Bh#Bh$Bh$BBB B!B!B"B#B#B$B%BhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBgBgBg Bg Bg!Bg"Bg"Bg#Bg$Bg$BBB B!B!B"B#B#B$B%BgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBfBfBf Bf Bf!Bf"Bf"Bf#Bf$Bf$BBB B!B!B"B#B#B$B%BfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBeBeBeBeBeBeBeBeBeBeBBBBBBBBBBBeBeBe Be Be!Be"Be"Be#Be$Be$BBB B!B!B"B#B#B$B%BeBeBeBeBeBeBeBeBeBeBBBBBBBBBBsegyio-1.8.3/test-data/small-ps-dec-il-inc-xl-off.sgy0000664000372000037200000002412013407674361021673 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  BhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBhBhBh Bh Bh!Bh"Bh"Bh#Bh$Bh$BBB B!B!B"B#B#B$B%BhBhBhBhBhBhBhBhBhBhBBBBBBBBBBBgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBgBgBg Bg Bg!Bg"Bg"Bg#Bg$Bg$BBB B!B!B"B#B#B$B%BgBgBgBgBgBgBgBgBgBgBBBBBBBBBBBfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBfBfBf Bf Bf!Bf"Bf"Bf#Bf$Bf$BBB B!B!B"B#B#B$B%BfBfBfBfBfBfBfBfBfBfBBBBBBBBBBBeBeBeBeBeBeBeBeBeBeBBBBBBBBBBBeBeBe Be Be!Be"Be"Be#Be$Be$BBB B!B!B"B#B#B$B%BeBeBeBeBeBeBeBeBeBeBBBBBBBBBBsegyio-1.8.3/test-data/obtuse-small.sgy0000664000372000037200000003441013407674361017462 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2ddA33A3=A3HA3RA3]A3gA3rA3|A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A4$A4.A49A4CA4NA4XA4cA4mA4xA4A4A4A4A4A4A4A4A4A4A4A4A5A5 A5A5 A5*A55ecA\)A\3A\=A\HA\RA\]A\gA\rA\|A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A]$A]/A]9A]DA]NA]YA]cA]nA]xA]A]A]A]A]A]A]A]A]A]A]A]A^A^ A^A^ A^*fbAA)A3A>AHASA]AhArA}AAAAAAAAAAAAAAAA$A/A9ADANAYAcAnAxAAAAAAAAAAAAAA AA gaAAA)A4A>AHASA]AhArA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA Ah`A AAA)A4A>AIASA^AhAsA}A׈AגAםAקAײA׼AAAAAAAAAA%A/A:ADAOAYAdAnAyA؃A؎AؘAأAحAظAAAAAAAA ccA#33A#3=A#3HA#3RA#3]A#3gA#3rA#3|A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#4A#4A#4A#4$A#4.A#49A#4CA#4NA#4XA#4cA#4mA#4xA#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#5A#5 A#5A#5 A#5*A#55dbA#\)A#\3A#\>A#\HA#\SA#\]A#\hA#\rA#\|A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#]A#]A#]A#]$A#]/A#]9A#]DA#]NA#]YA#]cA#]nA#]xA#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#^A#^ A#^A#^ A#^*eaA#A#)A#3A#>A#HA#SA#]A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#$A#/A#9A#DA#NA#YA#cA#nA#xA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# f`A#A#A#)A#4A#>A#IA#SA#^A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#g_A# A#A#A#)A#4A#>A#IA#SA#^A#hA#sA#}A#׈A#גA#םA#קA#ײA#׼A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#؃A#؎A#ؘA#أA#حA#ظA#A#A#A#A#A#A#A# bbA333A33=A33HA33RA33]A33gA33rA33|A33A33A33A33A33A33A33A33A33A33A33A33A34A34A34A34$A34.A349A34CA34NA34XA34cA34mA34xA34A34A34A34A34A34A34A34A34A34A34A34A35A35 A35A35 A35*A355caA3\)A3\3A3\>A3\HA3\SA3\]A3\hA3\rA3\|A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3]A3]A3]A3]$A3]/A3]9A3]DA3]NA3]YA3]cA3]nA3]xA3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3^A3^ A3^A3^ A3^*d`A3A3)A33A3>A3HA3SA3]A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3$A3/A39A3DA3NA3YA3cA3nA3xA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 e_A3A3A3)A34A3>A3IA3SA3^A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3f^A3 A3A3A3)A34A3>A3IA3SA3^A3hA3sA3}A3׈A3גA3םA3קA3ײA3׼A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3؃A3؎A3ؘA3أA3حA3ظA3A3A3A3A3A3A3A3 aaAC33AC3=AC3HAC3RAC3]AC3gAC3rAC3|AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC4AC4AC4AC4$AC4/AC49AC4DAC4NAC4YAC4cAC4nAC4xAC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC5AC5 AC5AC5 AC5*AC55b`AC\)AC\3AC\>AC\HAC\SAC\]AC\hAC\rAC\}AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC]AC]AC]AC]$AC]/AC]9AC]DAC]NAC]YAC]cAC]nAC]xAC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC^AC^ AC^AC^ AC^+c_ACAC)AC3AC>ACHACSAC]AChACrAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC d^ACACAC)AC4AC>ACIACSAC^AChACsAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACe]AC ACACAC)AC4AC>ACIACSAC^AChACsAC}AC׈ACגACםACקACײAC׼ACACACACACACACACACAC%AC0AC:ACEACOACZACdACoACyAC؃AC؎ACؘACأACحACظACACACACACACACAC ``AS33AS3=AS3HAS3RAS3]AS3gAS3rAS3|AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS4AS4AS4AS4$AS4/AS49AS4DAS4NAS4YAS4cAS4nAS4xAS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS5AS5 AS5AS5 AS5*AS55a_AS\)AS\3AS\>AS\HAS\SAS\]AS\hAS\rAS\}AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS]AS]AS]AS]$AS]/AS]9AS]DAS]NAS]YAS]cAS]nAS]xAS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS^AS^ AS^AS^ AS^+b^ASAS)AS3AS>ASHASSAS]AShASrAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS c]ASASAS)AS4AS>ASIASSAS^AShASsAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASd\AS ASASAS)AS4AS>ASIASSAS^AShASsAS}AS׈ASגASםASקASײAS׼ASASASASASASASASASAS%AS0AS:ASEASOASZASdASoASyAS؃AS؎ASؘASأASحASظASASASASASASASAS segyio-1.8.3/test-data/normal-small.sgy0000664000372000037200000003441013407674361017451 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2 A33A3=A3HA3RA3]A3gA3rA3|A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A4$A4.A49A4CA4NA4XA4cA4mA4xA4A4A4A4A4A4A4A4A4A4A4A4A5A5 A5A5 A5*A55 A\)A\3A\=A\HA\RA\]A\gA\rA\|A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A]$A]/A]9A]DA]NA]YA]cA]nA]xA]A]A]A]A]A]A]A]A]A]A]A]A^A^ A^A^ A^* AA)A3A>AHASA]AhArA}AAAAAAAAAAAAAAAA$A/A9ADANAYAcAnAxAAAAAAAAAAAAAA AA  AAA)A4A>AHASA]AhArA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA A A AAA)A4A>AIASA^AhAsA}A׈AגAםAקAײA׼AAAAAAAAAA%A/A:ADAOAYAdAnAyA؃A؎AؘAأAحAظAAAAAAAA  A#33A#3=A#3HA#3RA#3]A#3gA#3rA#3|A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#4A#4A#4A#4$A#4.A#49A#4CA#4NA#4XA#4cA#4mA#4xA#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#5A#5 A#5A#5 A#5*A#55 A#\)A#\3A#\>A#\HA#\SA#\]A#\hA#\rA#\|A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#]A#]A#]A#]$A#]/A#]9A#]DA#]NA#]YA#]cA#]nA#]xA#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#^A#^ A#^A#^ A#^* A#A#)A#3A#>A#HA#SA#]A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#$A#/A#9A#DA#NA#YA#cA#nA#xA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A#  A#A#A#)A#4A#>A#IA#SA#^A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#A#A#A#A#A#A#A#A#A#A#A#A#A# A# A# A#A#A#)A#4A#>A#IA#SA#^A#hA#sA#}A#׈A#גA#םA#קA#ײA#׼A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#؃A#؎A#ؘA#أA#حA#ظA#A#A#A#A#A#A#A#  A333A33=A33HA33RA33]A33gA33rA33|A33A33A33A33A33A33A33A33A33A33A33A33A34A34A34A34$A34.A349A34CA34NA34XA34cA34mA34xA34A34A34A34A34A34A34A34A34A34A34A34A35A35 A35A35 A35*A355 A3\)A3\3A3\>A3\HA3\SA3\]A3\hA3\rA3\|A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3]A3]A3]A3]$A3]/A3]9A3]DA3]NA3]YA3]cA3]nA3]xA3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3^A3^ A3^A3^ A3^* A3A3)A33A3>A3HA3SA3]A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3$A3/A39A3DA3NA3YA3cA3nA3xA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3  A3A3A3)A34A3>A3IA3SA3^A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3 A3 A3A3A3)A34A3>A3IA3SA3^A3hA3sA3}A3׈A3גA3םA3קA3ײA3׼A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3؃A3؎A3ؘA3أA3حA3ظA3A3A3A3A3A3A3A3  AC33AC3=AC3HAC3RAC3]AC3gAC3rAC3|AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC4AC4AC4AC4$AC4/AC49AC4DAC4NAC4YAC4cAC4nAC4xAC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC5AC5 AC5AC5 AC5*AC55 AC\)AC\3AC\>AC\HAC\SAC\]AC\hAC\rAC\}AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC]AC]AC]AC]$AC]/AC]9AC]DAC]NAC]YAC]cAC]nAC]xAC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC^AC^ AC^AC^ AC^+ ACAC)AC3AC>ACHACSAC]AChACrAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC  ACACAC)AC4AC>ACIACSAC^AChACsAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC AC AC ACACAC)AC4AC>ACIACSAC^AChACsAC}AC׈ACגACםACקACײAC׼ACACACACACACACACACAC%AC0AC:ACEACOACZACdACoACyAC؃AC؎ACؘACأACحACظACACACACACACACAC  AS33AS3=AS3HAS3RAS3]AS3gAS3rAS3|AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS4AS4AS4AS4$AS4/AS49AS4DAS4NAS4YAS4cAS4nAS4xAS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS5AS5 AS5AS5 AS5*AS55 AS\)AS\3AS\>AS\HAS\SAS\]AS\hAS\rAS\}AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS]AS]AS]AS]$AS]/AS]9AS]DAS]NAS]YAS]cAS]nAS]xAS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS^AS^ AS^AS^ AS^+ ASAS)AS3AS>ASHASSAS]AShASrAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS  ASASAS)AS4AS>ASIASSAS^AShASsAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS AS AS ASASAS)AS4AS>ASIASSAS^AShASsAS}AS׈ASגASםASקASײAS׼ASASASASASASASASASAS%AS0AS:ASEASOASZASdASoASyAS؃AS؎ASؘASأASحASظASASASASASASASAS segyio-1.8.3/test-data/Mx1.sgy0000664000372000037200000002412013407674361015515 0ustar travistravis@@@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  <Ŭ==u=)k=4m=> =If{=S=^_1BdBdBdBdBdBdBdBdBdBdBBBBBBBBBBCCCCCCCCCCAA AAA*A4A>AIASA^BeBeBeBeBeBeBeBeBeBeBBBBBBBBBBCCCCCCCCCCA A A A A *A 4A ?A IA TA ^BfBfBfBfBfBfBfBfBfBfBBBBBBBBBBCCCCCCCCCCA0A0 A0A0A0*A04A0?A0IA0TA0^BgBgBgBgBgBgBgBgBgBgBBBBBBBBBBCCCCCCCCCCA@A@ A@A@A@*A@4A@?A@IA@TA@^BhBhBhBhBhBhBhBhBhBhBBBBBBBBBBCCCCCCCCCCAPAP APAPAP*AP4AP?APIAPTAP^BiBiBiBiBiBiBiBiBiBiBBBBBBBBBBCCCCCCCCCCsegyio-1.8.3/test-data/multi-text.sgy0000664000372000037200000004040413407674361017167 0ustar travistravis@@@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ segyio-1.8.3/test-data/acute-small.sgy0000664000372000037200000003441013407674361017262 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2dA33A3=A3HA3RA3]A3gA3rA3|A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A4$A4.A49A4CA4NA4XA4cA4mA4xA4A4A4A4A4A4A4A4A4A4A4A4A5A5 A5A5 A5*A55eA\)A\3A\=A\HA\RA\]A\gA\rA\|A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A]$A]/A]9A]DA]NA]YA]cA]nA]xA]A]A]A]A]A]A]A]A]A]A]A]A^A^ A^A^ A^*fAA)A3A>AHASA]AhArA}AAAAAAAAAAAAAAAA$A/A9ADANAYAcAnAxAAAAAAAAAAAAAA AA gAAA)A4A>AHASA]AhArA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA AhA AAA)A4A>AIASA^AhAsA}A׈AגAםAקAײA׼AAAAAAAAAA%A/A:ADAOAYAdAnAyA؃A؎AؘAأAحAظAAAAAAAA cA#33A#3=A#3HA#3RA#3]A#3gA#3rA#3|A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#3A#4A#4A#4A#4$A#4.A#49A#4CA#4NA#4XA#4cA#4mA#4xA#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#4A#5A#5 A#5A#5 A#5*A#55dA#\)A#\3A#\>A#\HA#\SA#\]A#\hA#\rA#\|A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#\A#]A#]A#]A#]$A#]/A#]9A#]DA#]NA#]YA#]cA#]nA#]xA#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#]A#^A#^ A#^A#^ A#^*eA#A#)A#3A#>A#HA#SA#]A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#$A#/A#9A#DA#NA#YA#cA#nA#xA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#A# fA#A#A#)A#4A#>A#IA#SA#^A#hA#rA#}A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#A#A#A#A#A#A#A#A#A#A#A#A#A# A#gA# A#A#A#)A#4A#>A#IA#SA#^A#hA#sA#}A#׈A#גA#םA#קA#ײA#׼A#A#A#A#A#A#A#A#A#A#%A#/A#:A#DA#OA#YA#dA#nA#yA#؃A#؎A#ؘA#أA#حA#ظA#A#A#A#A#A#A#A# bA333A33=A33HA33RA33]A33gA33rA33|A33A33A33A33A33A33A33A33A33A33A33A33A34A34A34A34$A34.A349A34CA34NA34XA34cA34mA34xA34A34A34A34A34A34A34A34A34A34A34A34A35A35 A35A35 A35*A355cA3\)A3\3A3\>A3\HA3\SA3\]A3\hA3\rA3\|A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3\A3]A3]A3]A3]$A3]/A3]9A3]DA3]NA3]YA3]cA3]nA3]xA3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3]A3^A3^ A3^A3^ A3^*dA3A3)A33A3>A3HA3SA3]A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3$A3/A39A3DA3NA3YA3cA3nA3xA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3A3 eA3A3A3)A34A3>A3IA3SA3^A3hA3rA3}A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3A3A3A3A3A3A3A3A3A3A3A3A3A3 A3fA3 A3A3A3)A34A3>A3IA3SA3^A3hA3sA3}A3׈A3גA3םA3קA3ײA3׼A3A3A3A3A3A3A3A3A3A3%A3/A3:A3DA3OA3YA3dA3nA3yA3؃A3؎A3ؘA3أA3حA3ظA3A3A3A3A3A3A3A3 aAC33AC3=AC3HAC3RAC3]AC3gAC3rAC3|AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC3AC4AC4AC4AC4$AC4/AC49AC4DAC4NAC4YAC4cAC4nAC4xAC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC4AC5AC5 AC5AC5 AC5*AC55bAC\)AC\3AC\>AC\HAC\SAC\]AC\hAC\rAC\}AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC\AC]AC]AC]AC]$AC]/AC]9AC]DAC]NAC]YAC]cAC]nAC]xAC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC]AC^AC^ AC^AC^ AC^+cACAC)AC3AC>ACHACSAC]AChACrAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACAC dACACAC)AC4AC>ACIACSAC^AChACsAC}ACACACACACACACACACACACACACACACAC%AC/AC:ACDACOACYACdACnACyACACACACACACACACACACACACACAC ACeAC ACACAC)AC4AC>ACIACSAC^AChACsAC}AC׈ACגACםACקACײAC׼ACACACACACACACACACAC%AC0AC:ACEACOACZACdACoACyAC؃AC؎ACؘACأACحACظACACACACACACACAC `AS33AS3=AS3HAS3RAS3]AS3gAS3rAS3|AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS3AS4AS4AS4AS4$AS4/AS49AS4DAS4NAS4YAS4cAS4nAS4xAS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS4AS5AS5 AS5AS5 AS5*AS55aAS\)AS\3AS\>AS\HAS\SAS\]AS\hAS\rAS\}AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS\AS]AS]AS]AS]$AS]/AS]9AS]DAS]NAS]YAS]cAS]nAS]xAS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS]AS^AS^ AS^AS^ AS^+bASAS)AS3AS>ASHASSAS]AShASrAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASAS cASASAS)AS4AS>ASIASSAS^AShASsAS}ASASASASASASASASASASASASASASASAS%AS/AS:ASDASOASYASdASnASyASASASASASASASASASASASASASAS ASdAS ASASAS)AS4AS>ASIASSAS^AShASsAS}AS׈ASגASםASקASײAS׼ASASASASASASASASASAS%AS0AS:ASEASOASZASdASoASyAS؃AS؎ASؘASأASحASظASASASASASASASAS segyio-1.8.3/test-data/small-lsb.sgy0000664000372000037200000003441013407674361016741 0ustar travistravis@@z@``@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@晉@@@M]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@z@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@@@@j@@@`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`@j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 233A=3AH3AR3A]3Ag3Ar3A|3A3A3A3A3A3A3A3A3A3A3A3A3A4A4A4A$4A.4A94AC4AN4AX4Ac4Am4Ax4A4A4A4A4A4A4A4A4A4A4A4A4A5A 5A5A 5A*5A55A)\A3\A=\AH\AR\A]\Ag\Ar\A|\A\A\A\A\A\A\A\A\A\A\A\A\A]A]A]A$]A/]A9]AD]AN]AY]Ac]An]Ax]A]A]A]A]A]A]A]A]A]A]A]A]A^A ^A^A ^A*^AA)A3A>AHASA]AhArA}AAAAAAAƅAхAۅAAAAAAA$A/A9ADANAYAcAnAxAAAAAAA†ĂA׆AAAAA AA AAA)A4A>AHASA]AhArA}AAAAAAAƮAѮAۮAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAA¯A̯AׯAAAAA AA AAA)A4A>AIASA^AhAsA}AAAAAAAAAAAAAAAA%A/A:ADAOAYAdAnAyAAAAAAAAAAAAAA A33#A=3#AH3#AR3#A]3#Ag3#Ar3#A|3#A3#A3#A3#A3#A3#A3#A3#A3#A3#A3#A3#A3#A4#A4#A4#A$4#A.4#A94#AC4#AN4#AX4#Ac4#Am4#Ax4#A4#A4#A4#A4#A4#A4#A4#A4#A4#A4#A4#A4#A5#A 5#A5#A 5#A*5#A55#A)\#A3\#A>\#AH\#AS\#A]\#Ah\#Ar\#A|\#A\#A\#A\#A\#A\#A\#A\#A\#A\#A\#A\#A\#A]#A]#A]#A$]#A/]#A9]#AD]#AN]#AY]#Ac]#An]#Ax]#A]#A]#A]#A]#A]#A]#A]#A]#A]#A]#A]#A]#A^#A ^#A^#A ^#A*^#A#A)#A3#A>#AH#AS#A]#Ah#Ar#A}#A#A#A#A#A#A#Aƅ#Aх#Aۅ#A#A#A#A#A#A#A$#A/#A9#AD#AN#AY#Ac#An#Ax#A#A#A#A#A#A#A†#Ă#A׆#A#A#A#A#A #A#A #A#A#A)#A4#A>#AI#AS#A^#Ah#Ar#A}#A#A#A#A#A#A#AƮ#AѮ#Aۮ#A#A#A#A#A#A#A%#A/#A:#AD#AO#AY#Ad#An#Ay#A#A#A#A#A#A#A¯#Aͯ#Aׯ#A#A#A#A#A #A#A #A#A#A)#A4#A>#AI#AS#A^#Ah#As#A}#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A#A%#A/#A:#AD#AO#AY#Ad#An#Ay#A#A#A#A#A#A#A#A#A#A#A#A#A#A #A333A=33AH33AR33A]33Ag33Ar33A|33A33A33A33A33A33A33A33A33A33A33A33A33A43A43A43A$43A.43A943AC43AN43AX43Ac43Am43Ax43A43A43A43A43A43A43A43A43A43A43A43A43A53A 53A53A 53A*53A553A)\3A3\3A>\3AH\3AS\3A]\3Ah\3Ar\3A|\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A]3A]3A]3A$]3A/]3A9]3AD]3AN]3AY]3Ac]3An]3Ax]3A]3A]3A]3A]3A]3A]3A]3A]3A]3A]3A]3A]3A^3A ^3A^3A ^3A*^3A3A)3A33A>3AH3AS3A]3Ah3Ar3A}3A3A3A3A3A3A3Aƅ3Aх3Aۅ3A3A3A3A3A3A3A$3A/3A93AD3AN3AY3Ac3An3Ax3A3A3A3A3A3A3A†3Ă3A׆3A3A3A3A3A 3A3A 3A3A3A)3A43A>3AI3AS3A^3Ah3Ar3A}3A3A3A3A3A3A3AƮ3AѮ3Aۮ3A3A3A3A3A3A3A%3A/3A:3AD3AO3AY3Ad3An3Ay3A3A3A3A3A3A3A¯3Aͯ3Aׯ3A3A3A3A3A 3A3A 3A3A3A)3A43A>3AI3AS3A^3Ah3As3A}3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A%3A/3A:3AD3AO3AY3Ad3An3Ay3A3A3A3A3A3A3A3A3A3A3A3A3A3A 3A33CA=3CAH3CAR3CA]3CAg3CAr3CA|3CA3CA3CA3CA3CA3CA3CA3CA3CA3CA3CA3CA3CA4CA4CA4CA$4CA/4CA94CAD4CAN4CAY4CAc4CAn4CAx4CA4CA4CA4CA4CA4CA4CA4CA4CA4CA4CA4CA4CA5CA 5CA5CA 5CA*5CA55CA)\CA3\CA>\CAH\CAS\CA]\CAh\CAr\CA}\CA\CA\CA\CA\CA\CA\CA\CA\CA\CA\CA\CA\CA]CA]CA]CA$]CA/]CA9]CAD]CAN]CAY]CAc]CAn]CAx]CA]CA]CA]CA]CA]CA]CA]CA]CA]CA]CA]CA]CA^CA ^CA^CA ^CA+^CACA)CA3CA>CAHCASCA]CAhCArCA}CACACACACACACAƅCAхCAۅCACACACACACACA%CA/CA:CADCAOCAYCAdCAnCAyCACACACACACACA†CĂCA׆CACACACACA CACA CACACA)CA4CA>CAICASCA^CAhCAsCA}CACACACACACACAǮCAѮCAۮCACACACACACACA%CA/CA:CADCAOCAYCAdCAnCAyCACACACACACACA¯CAͯCAׯCACACACACA CACA CACACA)CA4CA>CAICASCA^CAhCAsCA}CACACACACACACACACACACACACACACACA%CA0CA:CAECAOCAZCAdCAoCAyCACACACACACACACACACACACACACA CA33SA=3SAH3SAR3SA]3SAg3SAr3SA|3SA3SA3SA3SA3SA3SA3SA3SA3SA3SA3SA3SA3SA4SA4SA4SA$4SA/4SA94SAD4SAN4SAY4SAc4SAn4SAx4SA4SA4SA4SA4SA4SA4SA4SA4SA4SA4SA4SA4SA5SA 5SA5SA 5SA*5SA55SA)\SA3\SA>\SAH\SAS\SA]\SAh\SAr\SA}\SA\SA\SA\SA\SA\SA\SA\SA\SA\SA\SA\SA\SA]SA]SA]SA$]SA/]SA9]SAD]SAN]SAY]SAc]SAn]SAx]SA]SA]SA]SA]SA]SA]SA]SA]SA]SA]SA]SA]SA^SA ^SA^SA ^SA+^SASA)SA3SA>SAHSASSA]SAhSArSA}SASASASASASASAƅSAхSAۅSASASASASASASA%SA/SA:SADSAOSAYSAdSAnSAySASASASASASASA†SĂSA׆SASASASASA SASA SASASA)SA4SA>SAISASSA^SAhSAsSA}SASASASASASASAǮSAѮSAۮSASASASASASASA%SA/SA:SADSAOSAYSAdSAnSAySASASASASASASA¯SAͯSAׯSASASASASA SASA SASASA)SA4SA>SAISASSA^SAhSAsSA}SASASASASASASASASASASASASASASASA%SA0SA:SAESAOSAZSAdSAoSAySASASASASASASASASASASASASASA SAsegyio-1.8.3/mex/0000775000372000037200000000000013407674361013230 5ustar travistravissegyio-1.8.3/mex/segyspec_mex.c0000664000372000037200000001166113407674361016074 0ustar travistravis#include #include "mex.h" #include #include "segyutil.h" mxArray *createPLHSStruct() { int nfields = 11; const char *fnames[nfields]; fnames[0] = "filename"; fnames[1] = "sample_format"; fnames[2] = "crossline_indexes"; fnames[3] = "inline_indexes"; fnames[4] = "sample_indexes"; fnames[5] = "trace_sorting_format"; fnames[6] = "offset_count"; fnames[7] = "first_trace_pos"; fnames[8] = "il_stride"; fnames[9] = "xl_stride"; fnames[10] = "trace_bsize"; mxArray *plhs = mxCreateStructMatrix(1,1,nfields,fnames); return plhs; } void checkInputOutputSizes(int nlhs, int nrhs ) { /* check for proper number of arguments */ if(nrhs!=5) { mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","Four inputs required."); } if(nlhs!=1) { mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nlhs","One output required."); } } void checkInputOutput(int nlhs, mxArray **plhs, int nrhs, const mxArray **prhs) { checkInputOutputSizes(nlhs, nrhs); /* First input must be a string */ if ( mxIsChar(prhs[0]) != 1) { mexErrMsgIdAndTxt("SegyIo:segyspec:inputNotString", "Input must be a string."); } /* First input must be a row vector */ if (mxGetM(prhs[0])!=1) { mexErrMsgIdAndTxt("SegyIo:segyspec:inputNotVector", "Input must be a row vector."); } /* make sure the second input argument is int */ if( !mxIsNumeric(prhs[1]) || mxGetNumberOfElements(prhs[1])!=1 ) { mexErrMsgIdAndTxt("SegyIo:segyspec:notScalar","Input multiplier must be a numeric."); } /* make sure the third input argument is int */ if( !mxIsNumeric(prhs[2]) || mxGetNumberOfElements(prhs[2])!=1 ) { mexErrMsgIdAndTxt("SegyIo:segyspec:notScalar","Input multiplier must be a numeric."); } /* make sure the fourth input argument is double */ if( !mxIsDouble(prhs[3]) || mxGetNumberOfElements(prhs[3])!=1 ) { mexErrMsgIdAndTxt("SegyIo:segyspec:notScalar","Input multiplier must be a double."); } /* make sure the fifth input argument is double */ if( !mxIsDouble(prhs[4]) || mxGetNumberOfElements(prhs[4])!=1 ) { mexErrMsgIdAndTxt("SegyIo:segyspec:notScalar","Input multiplier must be a double."); } } /* The gateway function */ void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { plhs[0] = createPLHSStruct(); checkInputOutput(nlhs, plhs, nrhs, prhs); char *filename = mxArrayToString(prhs[0]); int il = (int)mxGetScalar(prhs[1]); int xl = (int)mxGetScalar(prhs[2]); double t0 = mxGetScalar(prhs[3]); double dt = mxGetScalar(prhs[4]); SegySpec spec; int errc = segyCreateSpec(&spec, filename, il, xl, t0 * 1000.0, dt); if (errc != 0) { goto FAILURE; } mxSetFieldByNumber(plhs[0], 0, 0, mxCreateString(spec.filename)); mxSetFieldByNumber(plhs[0], 0, 1, mxCreateDoubleScalar(spec.sample_format)); mxArray *crossline_indexes = mxCreateDoubleMatrix(spec.crossline_count, 1, mxREAL); double *crossline_indexes_ptr = mxGetPr(crossline_indexes); for (int i = 0; i < spec.crossline_count; i++) { crossline_indexes_ptr[i] = spec.crossline_indexes[i]; } mxSetFieldByNumber(plhs[0], 0, 2, crossline_indexes); mxArray *inline_indexes = mxCreateDoubleMatrix(spec.inline_count, 1, mxREAL); double *inline_indexes_ptr = mxGetPr(inline_indexes); for (int i = 0; i < spec.inline_count; i++) { inline_indexes_ptr[i] = spec.inline_indexes[i]; } mxSetFieldByNumber(plhs[0], 0, 3, inline_indexes); mxArray *mx_sample_indexes = mxCreateDoubleMatrix(spec.sample_count,1, mxREAL); double *mx_sample_indexes_ptr = mxGetPr(mx_sample_indexes); for (int i = 0; i < spec.sample_count; i++) { mx_sample_indexes_ptr[i] = spec.sample_indices[i]; } mxSetFieldByNumber(plhs[0], 0, 4, mx_sample_indexes); mxSetFieldByNumber(plhs[0], 0, 5, mxCreateDoubleScalar(spec.trace_sorting_format)); mxSetFieldByNumber(plhs[0], 0, 6, mxCreateDoubleScalar(spec.offset_count)); mxSetFieldByNumber(plhs[0], 0, 7, mxCreateDoubleScalar(spec.first_trace_pos)); mxSetFieldByNumber(plhs[0], 0, 8, mxCreateDoubleScalar(spec.il_stride)); mxSetFieldByNumber(plhs[0], 0, 9, mxCreateDoubleScalar(spec.xl_stride)); mxSetFieldByNumber(plhs[0], 0, 10, mxCreateDoubleScalar(spec.trace_bsize)); if (spec.crossline_indexes != NULL) free(spec.crossline_indexes); if (spec.inline_indexes != NULL) free(spec.inline_indexes); free(spec.sample_indices); if (spec.filename != NULL) free(spec.filename); mxFree(filename); return; FAILURE: { int nfields = 1; const char *fnames[nfields]; fnames[0] = "error"; plhs[0] = mxCreateStructMatrix(0,0, nfields, fnames); } mxFree(filename); } segyio-1.8.3/mex/TraceSortingFormat.m0000664000372000037200000000021413407674361017160 0ustar travistravisclassdef TraceSortingFormat < int32 % add comment here enumeration unknown (0) xline (1) iline (2) end end segyio-1.8.3/mex/segy_get_offsets_mex.c0000664000372000037200000000310513407674361017603 0ustar travistravis#include #include "mex.h" #include "matrix.h" #include "segyutil.h" #include void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int errc = SEGY_OK; if (nrhs != 4) { goto ERROR; } const mxArray* mx_spec = prhs[0]; const mxArray* mx_offset = prhs[1]; const mxArray* mx_il_word = prhs[2]; const mxArray* mx_xl_word = prhs[3]; SegySpec spec; recreateSpec(&spec, mx_spec); int offset = (int)mxGetScalar(mx_offset); int il = (int)mxGetScalar(mx_il_word); int xl = (int)mxGetScalar(mx_xl_word); segy_file* fp = segy_open( spec.filename, "rb" ); if( !fp ) { errc = SEGY_FOPEN_ERROR; goto ERROR; }; plhs[0] = mxCreateNumericMatrix(1, spec.offset_count, mxINT32_CLASS, mxREAL); int* int_offsets = mxMalloc(sizeof( int ) * spec.offset_count); errc = segy_offset_indices(fp, offset, spec.offset_count, int_offsets, spec.first_trace_pos, spec.trace_bsize); if( errc != SEGY_OK ) goto CLEANUP; int32_t* plhs0 = (int32_t*)mxGetData(plhs[0]); for( int i = 0; i < spec.offset_count; ++i ) plhs0[i] = int_offsets[i]; mxFree( int_offsets ); segy_close(fp); return; CLEANUP: segy_close(fp); ERROR: { int nfields = 1; const char *fnames[nfields]; fnames[0] = "error"; plhs[0] = mxCreateStructMatrix(0,0, nfields, fnames); mxSetFieldByNumber(plhs[0], 0, 0, mxCreateDoubleScalar(errc)); } } segyio-1.8.3/mex/SegySampleFormat.m0000664000372000037200000000051013407674361016624 0ustar travistravisclassdef SegySampleFormat < int32 % add comment here enumeration IBM_FLOAT_4_BYTE (1) SIGNED_INTEGER_4_BYTE (2) SIGNED_SHORT_2_BYTE (3) FIXED_POINT_WITH_GAIN_4_BYTE (4) IEEE_FLOAT_4_BYTE (5) NOT_IN_USE_1 (6) NOT_IN_USE_2 (7) SIGNED_CHAR_1_BYTE (8) end end segyio-1.8.3/mex/segyutil.c0000664000372000037200000001473413407674361015252 0ustar travistravis#include #include #include #include #include "segyutil.h" static char* copyString(const char* path) { size_t size = strlen(path) + 1; char* path_copy = malloc(size); memcpy(path_copy, path, size); return path_copy; } int segyCreateSpec(SegySpec* spec, const char* file, unsigned int inline_field, unsigned int crossline_field, float t0, float dt) { int errc = 0; segy_file* fp = segy_open( file, "rb" ); if (fp == NULL) { fprintf(stderr, "Unable to open file: '%s'\n", file); return -1; } spec->sample_indices = NULL; spec->inline_indexes = NULL; spec->crossline_indexes = NULL; char header[ SEGY_BINARY_HEADER_SIZE ]; errc = segy_binheader( fp, header ); if (errc!=0) { goto CLEANUP; } spec->filename = copyString(file); spec->sample_format = segy_format( header ); spec->sample_count = segy_samples( header ); spec->sample_indices = malloc(sizeof(float) * spec->sample_count); errc = segy_sample_indices(fp, t0, dt, spec->sample_count, spec->sample_indices ); if (errc != 0) { goto CLEANUP; } const long trace0 = segy_trace0( header ); spec->trace_bsize = segy_trace_bsize( segy_samples( header ) ); int traces; errc = segy_traces(fp, &traces, trace0, spec->trace_bsize); if (errc != 0) { goto CLEANUP; } errc = segy_offsets(fp, inline_field, crossline_field, traces, &spec->offset_count, trace0, spec->trace_bsize); if (errc != 0) { goto CLEANUP; } errc = segy_sorting(fp, inline_field, crossline_field, SEGY_TR_OFFSET, &spec->trace_sorting_format, trace0, spec->trace_bsize); if (errc != 0) { goto CLEANUP; } int* l1; int* l2; int field; if (spec->trace_sorting_format == SEGY_INLINE_SORTING) { field = crossline_field; l1 = &spec->inline_count; l2 = &spec->crossline_count; } else if (spec->trace_sorting_format == SEGY_CROSSLINE_SORTING) { field = inline_field; l2 = &spec->inline_count; l1 = &spec->crossline_count; } else { fprintf(stderr, "Unknown sorting\n"); goto CLEANUP; } errc = segy_count_lines(fp, field, spec->offset_count, l1, l2, trace0, spec->trace_bsize); if (errc != 0) { goto CLEANUP; } spec->inline_indexes = malloc(sizeof(int) * spec->inline_count); spec->crossline_indexes = malloc(sizeof(int) * spec->crossline_count); errc = segy_inline_indices(fp, inline_field, spec->trace_sorting_format, spec->inline_count, spec->crossline_count, spec->offset_count, spec->inline_indexes, trace0, spec->trace_bsize); if (errc != 0) { goto CLEANUP; } errc = segy_crossline_indices(fp, crossline_field, spec->trace_sorting_format, spec->inline_count, spec->crossline_count, spec->offset_count, spec->crossline_indexes, trace0, spec->trace_bsize); if (errc != 0) { goto CLEANUP; } spec->first_trace_pos = segy_trace0( header ); errc = segy_inline_stride(spec->trace_sorting_format, spec->inline_count, &spec->il_stride); if (errc != 0) { goto CLEANUP; } errc = segy_crossline_stride(spec->trace_sorting_format, spec->crossline_count, &spec->xl_stride); if (errc != 0) { goto CLEANUP; } segy_close(fp); return 0; CLEANUP: if (spec->crossline_indexes != NULL) free(spec->crossline_indexes); if (spec->inline_indexes != NULL) free(spec->inline_indexes); free(spec->sample_indices); free(spec->filename); segy_close(fp); return errc; } static int getMaxDim(mxArray* arr){ int n = mxGetN(arr); int m = mxGetM(arr); int max = m; if (n>m) max = n; return max; } void recreateSpec(SegySpec *spec, const mxArray* mex_spec) { spec->filename = mxArrayToString(mxGetProperty(mex_spec, 0, "filename")); spec->sample_format = (int)mxGetScalar(mxGetProperty(mex_spec, 0, "sample_format")); spec->trace_sorting_format = (int)mxGetScalar(mxGetProperty(mex_spec, 0, "trace_sorting_format")); spec->offset_count = (int)mxGetScalar(mxGetProperty(mex_spec, 0, "offset_count")); spec->first_trace_pos = (int)mxGetScalar(mxGetProperty(mex_spec, 0, "first_trace_pos")); spec->il_stride = (int)mxGetScalar(mxGetProperty(mex_spec, 0, "il_stride")); spec->xl_stride = (int)mxGetScalar(mxGetProperty(mex_spec, 0, "xl_stride")); spec->trace_bsize = (int)mxGetScalar(mxGetProperty(mex_spec, 0, "trace_bsize")); mxArray* crossline_indexes = mxGetProperty(mex_spec, 0, "crossline_indexes"); spec->crossline_count = getMaxDim(crossline_indexes); spec->crossline_indexes = mxGetData(crossline_indexes); mxArray* inline_indexes = mxGetProperty(mex_spec, 0, "inline_indexes"); spec->inline_count = getMaxDim(inline_indexes); spec->inline_indexes = mxGetData(inline_indexes); mxArray* sample_indexes = mxGetProperty(mex_spec, 0, "sample_indexes"); spec->sample_count = getMaxDim(sample_indexes); spec->sample_indices = mxGetData(sample_indexes); } struct segy_file_format buffmt( const char* binary ) { struct segy_file_format fmt; fmt.samples = segy_samples( binary ); fmt.trace_bsize = segy_trace_bsize( fmt.samples ); fmt.trace0 = segy_trace0( binary ); fmt.format = segy_format( binary ); fmt.traces = 0; return fmt; } struct segy_file_format filefmt( segy_file* fp ) { char binary[SEGY_BINARY_HEADER_SIZE]; int err = segy_binheader( fp, binary ); if( err != 0 ) mexErrMsgIdAndTxt( "segy:c:filemft", strerror( errno ) ); struct segy_file_format fmt = buffmt( binary ); err = segy_traces( fp, &fmt.traces, fmt.trace0, fmt.trace_bsize ); if( err == 0 ) return fmt; const char* msg1 = "segy:c:filefmt"; const char* msg2; if( err == SEGY_TRACE_SIZE_MISMATCH ) msg2 = "Number of traces not consistent with file size. File corrupt?"; else msg2 = strerror( errno ); mexErrMsgIdAndTxt( msg1, msg2 ); } segy_file* segyfopen( const mxArray* filename, const char* mode ) { const char* fname = mxArrayToString( filename ); segy_file* fp = segy_open( fname, mode ); int err = errno; mxFree( (void*)fname ); if( !fp ) mexErrMsgIdAndTxt( "segy:c:fopen", strerror( err ) ); return fp; } segyio-1.8.3/mex/Segy.m0000664000372000037200000007265013407674361014327 0ustar travistravisclassdef Segy % add comment here properties spec end methods(Static) function obj = readInLine(spec, index) obj = segy_read_write_line_mex(spec, index, max(size(spec.crossline_indexes)), spec.inline_indexes, spec.il_stride, spec.offset_count); end function obj = readCrossLine(spec, index) obj = segy_read_write_line_mex(spec, index, max(size(spec.inline_indexes)), spec.crossline_indexes, spec.xl_stride, spec.offset_count); end function obj = writeCrossLine(spec, data, index) segy_read_write_line_mex(spec, index, max(size(spec.inline_indexes)), spec.crossline_indexes, spec.xl_stride, spec.offset_count, data); obj = data; end function obj = writeInLine(spec, data, index) segy_read_write_line_mex(spec, index, max(size(spec.crossline_indexes)), spec.inline_indexes, spec.il_stride, spec.offset_count, data); obj = data; end function data = get_line(cube, dir, n) if strcmpi(dir, 'iline') data = segy_read_write_line_mex(cube, n, max(size(cube.crossline_indexes)), cube.inline_indexes, cube.il_stride, cube.offset_count); elseif strcmpi(dir, 'xline') data = segy_read_write_line_mex(cube, n, max(size(cube.inline_indexes)), cube.crossline_indexes, cube.xl_stride, cube.offset_count); else error('Only iline and xline are valid directions.'); end end function data = put_line(cube, data, dir, n) if strcmpi(dir, 'iline') segy_read_write_line_mex(cube, n, max(size(cube.crossline_indexes)), cube.inline_indexes, cube.il_stride, cube.offset_count, data); elseif strcmpi(dir, 'xline') segy_read_write_line_mex(cube, n, max(size(cube.inline_indexes)), cube.crossline_indexes, cube.xl_stride, cube.offset_count, data ); else error('Only iline and xline are valid directions.'); end end % Goal: % Fast reading of trace header words in segy file. % % Algorithm: % Use keyword as specified in available_headers. If byte location is % known byte2headerword converts to keyword. % % Inputs: % filename Filename of segyfile % headword Name of header word to read (example: 'cdp') % notype Optional. If number format is different than set in segy % header this can be set by notype. Valid numbers are 1,2,3,5 % and 8 as spesified by SEG-Y rev 1 standard. % % Output: % name meaning % tr_heads Header values function [tr_heads, notrace] = get_header(filename, headword, notype) if exist(filename, 'file') ~= 2 error('File does not exist') end % notype isn't really use so we ignore it (for interface compatilibty) if ischar(headword) headword = TraceField.(headword); end headword = int32(headword); [x, y] = segy_get_header_mex(filename, headword); tr_heads = x; notrace = y; end % [data,dt,notype] = get_traces(filename,n1,n2,notype) % % Goal: % Fast reading of traces in segy volume. Not for front-end use. Use % get_line / get_slice / get_subcube instead. % % Algorithm: % % % Inputs: % filename Filename of segyfile % n1 (Optional) First trace. If no first and last trace is % specified, all file is read. % n2 (Optional) Last trace. % notype Optional. If number format is different than set in segy % header this can be set by notype. Valid numbers are 1,2,3,5 % and 8 as spesified by SEG-Y rev 1 standard. % % Output: % data Traces read from file % dt Sample interval % notype Number format function [data, dt, notype] = get_traces( filename, n1, n2, notype ) if exist(filename, 'file') ~= 2 error('File does not exist') end if nargin < 2 n1 = 1; end if nargin < 3 n2 = 0; end if nargin < 4 notype = -1; end [data, dt, notype] = segy_get_traces_mex( filename, n1 - 1, n2 - 1, notype ); end %function ntraces = get_ntraces(filename); % % Goal % Count the number of traces in a segy file % % Inputs: % filename Filename of segyfile % % Output: % notrace number of traces % return 0 in case of error function notrace = get_ntraces( filename ) if exist(filename, 'file') ~= 2 error('File does not exist') end notrace = segy_get_ntraces_mex( filename ); end % Goal: % Interpret segy cube as a 3D cube and save information needed to access % the segy file as a cube in terms of inline and crossline numbers. % % inputs: % filename filename of segy file % il_word bytenumber or header word for inline number % xl_word bytenumber or header word for crossline number % t0 Time (ms) / depth (m) of first sample. Optional (default = 0) % % output: % segycube struct needed to access segy file as a cube. function segycube = interpret_segycube(filename, il_word, xl_word, t0) if exist(filename, 'file') ~= 2 error('File does not exist') end if nargin < 4 t0 = 0; end if nargin < 3 xl_word = TraceField.Crossline3D; end if nargin < 2 il_word = TraceField.Inline3D; end % for compatibility with old code; if argument is passed as a % string, first convert to an enum, then pass that enum to the % constructor if ischar(il_word) il_word = TraceField.(il_word); end if ischar(xl_word) xl_word = TraceField.(xl_word); end segycube = SegySpec(filename, il_word, xl_word, t0); end % Goal: % Interpret segy cube as a 3D cube and save information needed to access % the segy file as a cube in terms of inline and crossline numbers. % % inputs: % name meaning % filename filename of segy file % offset bytenumber or header word for offset number % il_word bytenumber or header word for inline number % xl_word bytenumber or header word for crossline number % t0 Time (ms) / depth (m) of first sample. Optional (default = 0) % % output: % name meaning % segycube struct needed to access segy file as a cube. Used by % get_ps_line.m, put_ps_line.m and possibly friends function segycube = parse_ps_segycube(filename, offset, il_word, xl_word, t0) if ~exist('offset', 'var') || isempty(offset) offset = TraceField.offset; end if ~exist('il_word', 'var') || isempty(il_word) il_word = TraceField.Inline3D; end if ~exist('xl_word', 'var') || isempty(xl_word) xl_word = TraceField.Crossline3D; end if ~exist('t0', 'var') || isempty(t0) t0 = 0; end if ischar(il_word) il_word = TraceField.(il_word); end if ischar(xl_word) xl_word = TraceField.(xl_word); end if ischar(offset) offset = TraceField.(offset); end offset = int32(offset); il_word = int32(il_word); xl_word = int32(xl_word); t0 = double(t0); segycube = Segy.interpret_segycube(filename, il_word, xl_word, t0); offsets = segy_get_offsets_mex(segycube, offset, il_word, xl_word); segycube.offset = offsets; end % Goal: % Read an inline / crosline from a cube. % % Inputs: % cube Data as an interpreted segy cube from % 'interpret_segycube.m' % dir Direction of desired line (iline / xline) as a string % n Inline / crossline number % % Output: % data Extracted line function data = get_ps_line(cube, dir, n) if nargin < 3 error('Too few arguments. Usage: Segy.get_ps_line(cube, dir, n)'); end if strcmpi(dir, 'iline') len = max(size(cube.crossline_indexes)); ix = cube.inline_indexes; st = cube.il_stride; elseif strcmpi(dir, 'xline') len = max(size(cube.inline_indexes)); ix = cube.crossline_indexes; st = cube.xl_stride; else error('Only iline and xline are valid directions.'); end tmp = segy_read_write_ps_line_mex(cube, n, len, ix, st); tmp = reshape(tmp, [], cube.offset_count); nt = length(cube.t); data = permute(reshape(tmp, nt, size(tmp, 1)/nt, []), [1 3 2]); end function data = put_ps_line(cube, data, dir, n) if nargin < 4 error('Too few arguments. Usage: Segy.put_ps_line(cube, data, dir, n)'); end if strcmpi(dir, 'iline') len = max(size(cube.crossline_indexes)); ix = cube.inline_indexes; st = cube.il_stride; elseif strcmpi(dir, 'xline') len = max(size(cube.inline_indexes)); ix = cube.crossline_indexes; st = cube.xl_stride; else error('Only iline and xline are valid directions.'); end tmp = permute( data, [1 3 2] ); segy_read_write_ps_line_mex( cube, n, len, ix, st, tmp ); end function data = get_cube(sc) data = Segy.get_traces(sc.filename); if sc.trace_sorting_format == TraceSortingFormat.iline data = reshape( data, size( sc.sample_indexes, 1 ), size( sc.xline, 1 ), size( sc.iline, 1 ) ); elseif sc.trace_sorting_format == TraceSortingFormat.xline data = reshape( data, size( sc.sample_indexes, 1 ), size( sc.iline, 1 ), size( sc.xline, 1 ) ); else warning('Sorting was not set properly. Data returned as single long line'); end end function [data, notype] = put_traces(filename, data, n1, n2, notype) if exist(filename, 'file') ~= 2 error('File does not exist') end if nargin < 2 error('Too few arguments. Usage: put_traces( filename, data, (optional): n1, n2, notype)') end if nargin < 3 n1 = 1; end if nargin < 4 n2 = 0; end if nargin < 5 notype = -1; end % matlab uses 1-indexing, but C wants its positions 0-indexed. [data, notype] = segy_put_traces_mex( filename, data, n1 - 1, n2 - 1, notype ); end % function SegyHeader = get_segy_header(filename) % % Goal: % Read segy header. Extended textual headers are not read % % Inputs: % filename Filename of segyfile % % Output: % SegyHeader Struct with entire segy header function SegyHeader = get_segy_header(filename) if exist(filename, 'file') ~= 2 error('File does not exist') end [ebcdic, bin] = segy_get_segy_header_mex( filename ); SegyHeader.ebcdic = ebcdic; SegyHeader.JobIdNumber = segy_get_bfield_mex( bin, 3201 ); SegyHeader.LineNumber = segy_get_bfield_mex( bin, 3205 ); SegyHeader.ReelNumber = segy_get_bfield_mex( bin, 3209 ); SegyHeader.NumberOfTracesPerEnsemble = segy_get_bfield_mex( bin, 3213 ); SegyHeader.NumberOfAuxTracesPerEnsemble = segy_get_bfield_mex( bin, 3215 ); SegyHeader.SampleInterval = segy_get_bfield_mex( bin, 3217 ); SegyHeader.SampleIntervalOriginal = segy_get_bfield_mex( bin, 3219 ); SegyHeader.NumberOfSamples = segy_get_bfield_mex( bin, 3221 ); SegyHeader.NumberOfSamplesOriginal = segy_get_bfield_mex( bin, 3223 ); SegyHeader.SampleFormat = 0; switch segy_get_bfield_mex( bin, 3225 ) case 1 SegyHeader.SampleFormat = 'IBM32'; case 2 SegyHeader.SampleFormat = 'INT32'; case 3 SegyHeader.SampleFormat = 'INT16'; case 4 SegyHeader.SampleFormat = 'Obsolete'; case 5 SegyHeader.SampleFormat = 'IEEE32'; case 6 SegyHeader.SampleFormat = 'NotUsed'; case 7 SegyHeader.SampleFormat = 'NotUsed'; case 8 SegyHeader.SampleFormat = 'INT8'; end SegyHeader.EnsembleFold = segy_get_bfield_mex( bin, 3227 ); SegyHeader.TraceSortingCode = 0; switch segy_get_bfield_mex( bin, 3229 ) case -1 SegyHeader.TraceSortingCode = 'Other'; case 0 SegyHeader.TraceSortingCode = 'Unknown'; case 1 SegyHeader.TraceSortingCode = 'AsRecorded'; case 2 SegyHeader.TraceSortingCode = 'CDP'; case 3 SegyHeader.TraceSortingCode = 'SingleFoldContinuousProfile'; case 4 SegyHeader.TraceSortingCode = 'HorizontallyStacked'; case 5 SegyHeader.TraceSortingCode = 'CommonSourcePoint'; case 6 SegyHeader.TraceSortingCode = 'CommonReceiverPoint'; case 7 SegyHeader.TraceSortingCode = 'CommonOffsetPoint'; case 8 SegyHeader.TraceSortingCode = 'CommonMidPoint'; case 9 SegyHeader.TraceSortingCode = 'CommonConversionPoint'; end SegyHeader.VerticalSumCode = [num2str(segy_get_bfield_mex( bin, 3231 )), '_Sum']; SegyHeader.SweepFrequencyAtStart = segy_get_bfield_mex( bin, 3233 ); SegyHeader.SweepFrequencyAtEnd = segy_get_bfield_mex( bin, 3235 ); SegyHeader.SweepLength = segy_get_bfield_mex( bin, 3237 ); SegyHeader.SweepTypeCode = 0; switch segy_get_bfield_mex( bin, 3239 ) case 1 SegyHeader.SweepTypeCode = 'Linear'; case 2 SegyHeader.SweepTypeCode = 'Parabolic'; case 3 SegyHeader.SweepTypeCode = 'Exponential'; case 4 SegyHeader.SweepTypeCode = 'Other'; end SegyHeader.TraceNoOfSweepChannel = segy_get_bfield_mex( bin, 3241 ); SegyHeader.SweepTraceTaperLenghtStart = segy_get_bfield_mex( bin, 3243 ); SegyHeader.SweepTraceTaperLenghtEnd = segy_get_bfield_mex( bin, 3245 ); SegyHeader.TaperType = 0; switch segy_get_bfield_mex( bin, 3247 ) case 1 SegyHeader.TaperType = 'Linear'; case 2 SegyHeader.TaperType = 'Cos^2'; case 3 SegyHeader.TaperType = 'Other'; end SegyHeader.CorrelatedDataTraces = 0; switch segy_get_bfield_mex( bin, 3249 ) case 1 SegyHeader.CorrelatedDataTraces = 'No'; case 2 SegyHeader.CorrelatedDataTraces = 'Yes'; end SegyHeader.BinaryGainRecovered = 0; switch segy_get_bfield_mex( bin, 3251 ) case 1 SegyHeader.BinaryGainRecovered = 'Yes'; case 2 SegyHeader.BinaryGainRecovered = 'No'; end SegyHeader.AmplitudeRecoveryMethod = 0; switch segy_get_bfield_mex( bin, 3253 ) case 1 SegyHeader.AmplitudeRecoveryMethod = 'None'; case 2 SegyHeader.AmplitudeRecoveryMethod = 'SphericalDivergence'; case 3 SegyHeader.AmplitudeRecoveryMethod = 'AGC'; case 4 SegyHeader.AmplitudeRecoveryMethod = 'Other'; end SegyHeader.MeasurementSystem = 0; switch segy_get_bfield_mex( bin, 3255 ) case 1 SegyHeader.MeasurementSystem = 'Meter'; case 2 SegyHeader.MeasurementSystem = 'Feet'; end SegyHeader.ImpulseSignalPolarity = 0; switch segy_get_bfield_mex( bin, 3257 ) case 1 SegyHeader.ImpulseSignalPolarity = 'IncreasePressureNegativeNumber'; case 2 SegyHeader.ImpulseSignalPolarity = 'IncreasePressurePositiveNumber'; end SegyHeader.VibratorPolarityCode = 0; switch segy_get_bfield_mex( bin, 3259 ) case 1 SegyHeader.VibratorPolarityCode = '337.5-22.5'; case 2 SegyHeader.VibratorPolarityCode = '22.5-67.5'; case 3 SegyHeader.VibratorPolarityCode = '67.5-112.5'; case 4 SegyHeader.VibratorPolarityCode = '112.5-157.5'; case 5 SegyHeader.VibratorPolarityCode = '157.5-202.5'; case 6 SegyHeader.VibratorPolarityCode = '202.5-247.5'; case 7 SegyHeader.VibratorPolarityCode = '247.5-292.5'; case 8 SegyHeader.VibratorPolarityCode = '292.5-337.5'; end SegyHeader.FormatRevisionNumber = segy_get_bfield_mex( bin, 3501 ); SegyHeader.FixedLengthTraceFlag = segy_get_bfield_mex( bin, 3503 ); SegyHeader.NumberOfExtTextHeaders = segy_get_bfield_mex( bin, 3505 ); end % [tr_heads,notrace] = get_trace_header(filename,itrace); % % Goal: % Read the full trace header of the trace itrace % % Inputs: % filename Filename of segyfile % itrace trace number % % Output: % tr_heads Header values % notrace number of traces in segy file % function [tr_heads, notrace] = get_trace_header(filename, itrace) [header, notrace] = segy_get_trace_header_mex( filename, itrace ); % read trace header tr_heads.TraceSequenceLine = segy_get_field_mex( header, 1 ); tr_heads.TraceSequenceFile = segy_get_field_mex( header, 5 ); tr_heads.FieldRecord = segy_get_field_mex( header, 9 ); tr_heads.TraceNumber = segy_get_field_mex( header, 13 ); tr_heads.EnergySourcePoint = segy_get_field_mex( header, 17 ); tr_heads.cdp = segy_get_field_mex( header, 21 ); tr_heads.cdpTrace = segy_get_field_mex( header, 25 ); tr_heads.TraceIdenitifactionCode = segy_get_field_mex( header, 29 ); tr_heads.NSummedTraces = segy_get_field_mex( header, 31 ); tr_heads.NStackedTraces = segy_get_field_mex( header, 33 ); tr_heads.DataUse = segy_get_field_mex( header, 35 ); tr_heads.offset = segy_get_field_mex( header, 37 ); tr_heads.ReceiverGroupElevation = segy_get_field_mex( header, 41 ); tr_heads.SourceSurfaceElevation = segy_get_field_mex( header, 45 ); tr_heads.SourceDepth = segy_get_field_mex( header, 49 ); tr_heads.ReceiverDatumElevation = segy_get_field_mex( header, 53 ); tr_heads.SourceDatumElevation = segy_get_field_mex( header, 57 ); tr_heads.SourceWaterDepth = segy_get_field_mex( header, 61 ); tr_heads.GroupWaterDepth = segy_get_field_mex( header, 65 ); tr_heads.ElevationScalar = segy_get_field_mex( header, 69 ); tr_heads.SourceGroupScalar = segy_get_field_mex( header, 71 ); tr_heads.SourceX = segy_get_field_mex( header, 73 ); tr_heads.SourceY = segy_get_field_mex( header, 77 ); tr_heads.GroupX = segy_get_field_mex( header, 81 ); tr_heads.GroupY = segy_get_field_mex( header, 85 ); tr_heads.CoordinateUnits = segy_get_field_mex( header, 89 ); tr_heads.WeatheringVelocity = segy_get_field_mex( header, 91 ); tr_heads.SubWeatheringVelocity = segy_get_field_mex( header, 93 ); tr_heads.SourceUpholeTime = segy_get_field_mex( header, 95 ); tr_heads.GroupUpholeTime = segy_get_field_mex( header, 97 ); tr_heads.SourceStaticCorrection = segy_get_field_mex( header, 99 ); tr_heads.GroupStaticCorrection = segy_get_field_mex( header, 101 ); tr_heads.TotalStaticApplied = segy_get_field_mex( header, 103 ); tr_heads.LagTimeA = segy_get_field_mex( header, 105 ); tr_heads.LagTimeB = segy_get_field_mex( header, 107 ); tr_heads.DelayRecordingTime = segy_get_field_mex( header, 109 ); tr_heads.MuteTimeStart = segy_get_field_mex( header, 111 ); tr_heads.MuteTimeEND = segy_get_field_mex( header, 113 ); tr_heads.ns = segy_get_field_mex( header, 115 ); tr_heads.dt = segy_get_field_mex( header, 117 ); tr_heads.GainType = segy_get_field_mex( header, 119 ); tr_heads.InstrumentGainConstant = segy_get_field_mex( header, 121 ); tr_heads.InstrumentInitialGain = segy_get_field_mex( header, 123 ); tr_heads.Correlated = segy_get_field_mex( header, 125 ); tr_heads.SweepFrequenceStart = segy_get_field_mex( header, 127 ); tr_heads.SweepFrequenceEnd = segy_get_field_mex( header, 129 ); tr_heads.SweepLength = segy_get_field_mex( header, 131 ); tr_heads.SweepType = segy_get_field_mex( header, 133 ); tr_heads.SweepTraceTaperLengthStart = segy_get_field_mex( header, 135 ); tr_heads.SweepTraceTaperLengthEnd = segy_get_field_mex( header, 137 ); tr_heads.TaperType = segy_get_field_mex( header, 139 ); tr_heads.AliasFilterFrequency = segy_get_field_mex( header, 141 ); tr_heads.AliasFilterSlope = segy_get_field_mex( header, 143 ); tr_heads.NotchFilterFrequency = segy_get_field_mex( header, 145 ); tr_heads.NotchFilterSlope = segy_get_field_mex( header, 147 ); tr_heads.LowCutFrequency = segy_get_field_mex( header, 149 ); tr_heads.HighCutFrequency = segy_get_field_mex( header, 151 ); tr_heads.LowCutSlope = segy_get_field_mex( header, 153 ); tr_heads.HighCutSlope = segy_get_field_mex( header, 155 ); tr_heads.YearDataRecorded = segy_get_field_mex( header, 157 ); tr_heads.DayOfYear = segy_get_field_mex( header, 159 ); tr_heads.HourOfDay = segy_get_field_mex( header, 161 ); tr_heads.MinuteOfHour = segy_get_field_mex( header, 163 ); tr_heads.SecondOfMinute = segy_get_field_mex( header, 165 ); tr_heads.TimeBaseCode = segy_get_field_mex( header, 167 ); tr_heads.TraceWeightningFactor = segy_get_field_mex( header, 169 ); tr_heads.GeophoneGroupNumberRoll1 = segy_get_field_mex( header, 171 ); tr_heads.GeophoneGroupNumberFirstTraceOrigField = segy_get_field_mex( header, 173 ); tr_heads.GeophoneGroupNumberLastTraceOrigField = segy_get_field_mex( header, 175 ); tr_heads.GapSize = segy_get_field_mex( header, 177 ); tr_heads.OverTravel = segy_get_field_mex( header, 179 ); tr_heads.cdpX = segy_get_field_mex( header, 181 ); tr_heads.cdpY = segy_get_field_mex( header, 185 ); tr_heads.Inline3D = segy_get_field_mex( header, 189 ); tr_heads.Crossline3D = segy_get_field_mex( header, 193 ); tr_heads.ShotPoint = segy_get_field_mex( header, 197 ); tr_heads.ShotPointScalar = segy_get_field_mex( header, 201 ); tr_heads.TraceValueMeasurementUnit = segy_get_field_mex( header, 203 ); tr_heads.TransductionConstantMantissa = segy_get_field_mex( header, 205 ); tr_heads.TransductionConstantPower = segy_get_field_mex( header, 209 ); tr_heads.TransductionUnit = segy_get_field_mex( header, 211 ); tr_heads.TraceIdentifier = segy_get_field_mex( header, 213 ); tr_heads.ScalarTraceHeader = segy_get_field_mex( header, 215 ); tr_heads.SourceType = segy_get_field_mex( header, 217 ); tr_heads.SourceEnergyDirectionMantissa = segy_get_field_mex( header, 219 ); tr_heads.SourceEnergyDirectionExponent = segy_get_field_mex( header, 223 ); tr_heads.SourceMeasurementMantissa = segy_get_field_mex( header, 225 ); tr_heads.SourceMeasurementExponent = segy_get_field_mex( header, 229 ); tr_heads.SourceMeasurementUnit = segy_get_field_mex( header, 231 ); tr_heads.UnassignedInt1 = segy_get_field_mex( header, 233 ); tr_heads.UnassignedInt2 = segy_get_field_mex( header, 237 ); end % put_headers(filename,headers,headword) % % Goal: % Fast writing of trace header words in segy file. % % Inputs: % filename Filename of segyfile % headers Array of headervalues or single headervalue. Will be % written to all trace headers. If length of array is % different from number of traces in file an error will be % thrown. % headword Name of header word to be written (example: 'cdp') % function put_headers(filename, headers, headword) ntraces = Segy.get_ntraces( filename ); if and( ~isscalar(headers), max(size( headers )) ~= ntraces ) error( 'Inconsistent dimensions of header values' ) end % if single header value, create a traces-sized vector of that % header value, so that segy_put_headers_mex can always assume array if isscalar( headers ) headers = ones( 1, ntraces ) * headers; end if ischar(headword) headword = TraceField.(headword); end segy_put_headers_mex( filename, headers, int32(headword) ); end end end segyio-1.8.3/mex/segy_put_headers_mex.c0000664000372000037200000000307113407674361017600 0ustar travistravis#include #include #include #include "segyutil.h" #include "matrix.h" #include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { char* msg1; char* msg2; int err; segy_file* fp = segyfopen( prhs[ 0 ], "r+b" ); double* headers = mxGetPr( prhs[ 1 ] ); int field = mxGetScalar( prhs[ 2 ] ); struct segy_file_format fmt = filefmt( fp ); char traceheader[ SEGY_TRACE_HEADER_SIZE ]; /* * check that the field is valid and writing it won't return an error. by * checking it here we don't have to do it in the write loop */ err = segy_set_field( traceheader, field, 0 ); if( err != 0 ) { msg1 = "segy:put_headers:invalid_field"; msg2 = "Invalid field value/header offset"; goto cleanup; } double* itr = headers; for( int i = 0; i < fmt.traces; ++i, ++itr ) { err = segy_traceheader( fp, i, traceheader, fmt.trace0, fmt.trace_bsize ); const int val = *itr; if( err != 0 ) { msg1 = "segy:put_headers:os"; msg2 = strerror( errno ); goto cleanup; } segy_set_field( traceheader, field, val ); err = segy_write_traceheader( fp, i, traceheader, fmt.trace0, fmt.trace_bsize ); if( err != 0 ) { msg1 = "segy:put_headers:os"; msg2 = strerror( errno ); goto cleanup; } } segy_close( fp ); return; cleanup: segy_close( fp ); mexErrMsgIdAndTxt( msg1, msg2 ); } segyio-1.8.3/mex/segy_read_write_line_mex.c0000664000372000037200000000566413407674361020443 0ustar travistravis#include #include "mex.h" #include "matrix.h" #include "segyutil.h" #include /* The gateway function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { bool read; if (nrhs == 6) { read = true; } else if (nrhs == 7) { read = false; } else { goto ERROR; } const mxArray* mx_spec = prhs[0]; const mxArray* mx_index = prhs[1]; const mxArray* mx_line_length = prhs[2]; const mxArray* mx_line_indexes = prhs[3]; const mxArray* mx_stride = prhs[4]; const mxArray* mx_offsets = prhs[5]; SegySpec spec; recreateSpec(&spec,mx_spec); size_t index = (size_t)mxGetScalar(mx_index); uint32_t line_length = (uint32_t)mxGetScalar(mx_line_length); uint32_t* line_indexes = (uint32_t*)mxGetData(mx_line_indexes); int n = mxGetN(mx_line_indexes); int m = mxGetM(mx_line_indexes); uint32_t line_count = (n>m)? n:m; uint32_t stride = (uint32_t)mxGetScalar(mx_stride); int32_t offsets = (int32_t)mxGetScalar(mx_offsets); segy_file* fp; int line_trace0; int errc = segy_line_trace0( index, line_length, stride, offsets, line_indexes, line_count, &line_trace0 ); if (errc != 0) { goto CLEANUP; } if (read) { fp = segy_open( spec.filename, "rb" ); if (fp == NULL) { goto CLEANUP; } plhs[0] = mxCreateNumericMatrix(spec.sample_count, line_length, mxSINGLE_CLASS, mxREAL); float *data_ptr = (float *) mxGetData(plhs[0]); errc = segy_read_line( fp, line_trace0, line_length, stride, offsets, data_ptr, spec.first_trace_pos, spec.trace_bsize ); if (errc != 0) { goto CLEANUP; } errc = segy_to_native( spec.sample_format, line_length * spec.sample_count, data_ptr ); if (errc != 0) { goto CLEANUP; } } else { fp = segy_open( spec.filename, "r+b" ); if (fp == NULL) { goto CLEANUP; } const mxArray* mx_data = prhs[6]; float *data_ptr = (float *) mxGetData(mx_data); errc = segy_from_native( spec.sample_format, line_length * spec.sample_count, data_ptr ); if (errc != 0) { goto CLEANUP; } errc = segy_write_line( fp, line_trace0, line_length, stride, offsets, data_ptr, spec.first_trace_pos, spec.trace_bsize ); if (errc != 0) { goto CLEANUP; } errc = segy_to_native( spec.sample_format, line_length * spec.sample_count, data_ptr ); if (errc != 0) { goto CLEANUP; } } segy_close(fp); return; CLEANUP: segy_close(fp); ERROR: { int nfields = 1; const char *fnames[nfields]; fnames[0] = "error"; plhs[0] = mxCreateStructMatrix(0,0, nfields, fnames); mxSetFieldByNumber(plhs[0], 0, 0, mxCreateDoubleScalar(errc)); } } segyio-1.8.3/mex/TraceField.m0000664000372000037200000000536613407674361015422 0ustar travistravisclassdef TraceField < int32 % add comment here enumeration TraceSequenceLine (1) TraceSequenceFile (5) FieldRecord (9) TraceNumber (13) EnergySourcePoint (17) cdp (21) cdpTrace (25) TraceIdentificationCode (29) NSummedTraces (31) NStackedTraces (33) DataUse (35) offset (37) ReceiverGroupElevation (41) SourceSurfaceElevation (45) SourceDepth (49) ReceiverDatumElevation (53) SourceDatumElevation (57) SourceWaterDepth (61) GroupWaterDepth (65) ElevationScalar (69) SourceGroupScalar (71) SourceX (73) SourceY (77) GroupX (81) GroupY (85) CoordinateUnits (89) WeatheringVelocity (91) SubWeatheringVelocity (93) SourceUpholeTime (95) GroupUpholeTime (97) SourceStaticCorrection (99) GroupStaticCorrection (101) TotalStaticApplied (103) LagTimeA (105) LagTimeB (107) DelayRecordingTime (109) MuteTimeStart (111) MuteTimeEND (113) ns (115) dt (117) GainType (119) InstrumentGainConstant (121) InstrumentInitialGain (123) Correlated (125) SweepFrequenceStart (127) SweepFrequenceEnd (129) SweepLength (131) SweepType (133) SweepTraceTaperLengthStart (135) SweepTraceTaperLengthEnd (137) TaperType (139) AliasFilterFrequency (141) AliasFilterSlope (143) NotchFilterFrequency (145) NotchFilterSlope (147) LowCutFrequency (149) HighCutFrequency (151) LowCutSlope (153) HighCutSlope (155) YearDataRecorded (157) DayOfYear (159) HourOfDay (161) MinuteOfHour (163) SecondOfMinute (165) TimeBaseCode (167) TraceWeightningFactor (169) GeophoneGroupNumberRoll1 (171) GeophoneGroupNumberFirstTraceOrigField (173) GeophoneGroupNumberLastTraceOrigField (175) GapSize (177) OverTravel (179) cdpX (181) cdpY (185) Inline3D (189) Crossline3D (193) ShotPoint (197) ShotPointScalar (201) TraceValueMeasurementUnit (203) TransductionConstantMantissa (205) TransductionConstantPower (209) TransductionUnit (211) TraceIdentifier (213) ScalarTraceHeader (215) SourceType (217) SourceEnergyDirectionMantissa (219) SourceEnergyDirectionExponent (223) SourceMeasurementMantissa (225) SourceMeasurementExponent (229) SourceMeasurementUnit (231) UnassignedInt1 (233) UnassignedInt2 (237) end end segyio-1.8.3/mex/segy_get_trace_header_mex.c0000664000372000037200000000202513407674361020540 0ustar travistravis#include #include #include #include "segyutil.h" #include "matrix.h" #include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { char* msg1; char* msg2; int err; segy_file* fp = segyfopen( prhs[ 0 ], "rb" ); struct segy_file_format fmt = filefmt( fp ); int traceno = mxGetScalar( prhs[ 1 ] ); if( traceno > fmt.traces ) mexErrMsgIdAndTxt( "segy:get_trace_header:bounds", "Requested trace header does not exist in this file." ); mwSize dims[ 1 ] = { SEGY_TRACE_HEADER_SIZE }; plhs[ 0 ] = mxCreateCharArray( 1, dims ); err = segy_traceheader( fp, traceno, mxGetData( plhs[ 0 ] ), fmt.trace0, fmt.trace_bsize ); segy_close( fp ); if( err != 0 ) { msg1 = "segy:get_trace_header:os"; msg2 = strerror( errno ); goto cleanup; } plhs[ 1 ] = mxCreateDoubleScalar( fmt.traces ); return; cleanup: mexErrMsgIdAndTxt( msg1, msg2 ); } segyio-1.8.3/mex/segy_get_traces_mex.c0000664000372000037200000000371213407674361017417 0ustar travistravis#include #include #include #include "segyutil.h" #include "matrix.h" #include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { char* msg1; char* msg2; int err; segy_file* fp = segyfopen( prhs[ 0 ], "rb" ); int first_trace = mxGetScalar( prhs[ 1 ] ); int last_trace = mxGetScalar( prhs[ 2 ] ); int notype = mxGetScalar( prhs[ 3 ] ); struct segy_file_format fmt = filefmt( fp ); char binary[ SEGY_BINARY_HEADER_SIZE ]; err = segy_binheader( fp, binary ); if( err != 0 ) { msg1 = "segy:get_traces:binary"; msg2 = strerror( errno ); goto cleanup; } // if last_trace was defaulted we assign it to the last trace in the file if( last_trace == -1 ) last_trace = fmt.traces - 1; int traces = 1 + (last_trace - first_trace); long long bufsize = (long long)fmt.samples * traces; plhs[0] = mxCreateNumericMatrix( fmt.samples, traces, mxSINGLE_CLASS, mxREAL ); float* out = mxGetData( plhs[ 0 ] ); if( first_trace > last_trace ) { msg1 = "segy:get_traces:bounds"; msg2 = "first trace must be smaller than last trace"; goto cleanup; } for( int i = first_trace; i <= last_trace; ++i ) { err = segy_readtrace( fp, i, out, fmt.trace0, fmt.trace_bsize ); out += fmt.samples; if( err != 0 ) { msg1 = "segy:get_traces:segy_readtrace"; msg2 = strerror( errno ); goto cleanup; } } segy_close( fp ); if( notype != -1 ) fmt.format = notype; segy_to_native( fmt.format, bufsize, mxGetData( plhs[ 0 ] ) ); int interval; segy_get_bfield( binary, SEGY_BIN_INTERVAL, &interval ); plhs[ 1 ] = mxCreateDoubleScalar( interval ); plhs[ 2 ] = mxCreateDoubleScalar( fmt.format ); return; cleanup: segy_close( fp ); mexErrMsgIdAndTxt( msg1, msg2 ); } segyio-1.8.3/mex/segy_get_ntraces_mex.c0000664000372000037200000000052113407674361017570 0ustar travistravis#include #include "segyutil.h" #include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { segy_file* fp = segyfopen( prhs[ 0 ], "rb" ); struct segy_file_format fmt = filefmt( fp ); segy_close( fp ); plhs[0] = mxCreateDoubleScalar( fmt.traces ); } segyio-1.8.3/mex/segy_get_header_mex.c0000664000372000037200000000213013407674361017357 0ustar travistravis#include #include #include #include #include "segyutil.h" #include "matrix.h" #include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { char* msg1 = ""; char* msg2 = ""; int err; const char* filename = mxArrayToString( prhs[ 0 ] ); segy_file* fp = segyfopen( prhs[ 0 ], "rb" ); if( !fp ) goto cleanup; int field = mxGetScalar( prhs[ 1 ] ); struct segy_file_format fmt = filefmt( fp ); plhs[0] = mxCreateNumericMatrix( 1, fmt.traces, mxINT32_CLASS, mxREAL ); int* out = mxGetData( plhs[ 0 ] ); err = segy_field_forall( fp, field, 0, fmt.traces, 1, /* start, stop, step */ out, fmt.trace0, fmt.trace_bsize ); int no = errno; segy_close( fp ); if( err != SEGY_OK ) mexErrMsgIdAndTxt( "segy:get_header:forall", strerror( errno ) ); plhs[ 1 ] = mxCreateDoubleScalar( fmt.traces ); return; cleanup: mexErrMsgIdAndTxt( "segy:get_header:fopen", strerror( errno ) ); } segyio-1.8.3/mex/SegySpec.m0000664000372000037200000000321113407674361015125 0ustar travistravisclassdef SegySpec % add comment here properties filename sample_format trace_sorting_format sample_indexes crossline_indexes inline_indexes offset_count offset first_trace_pos il_stride xl_stride trace_bsize t iline xline sorting end methods function obj = SegySpec(filename, inline_field, crossline_field, t0) dt = 4; spec = segyspec_mex(filename, int32(inline_field), int32(crossline_field), t0, dt); obj.filename = filename; if (isempty(spec)) e = MException('SegySpec:NoSuchFile', 'File %s not found',filename); throw(e); end obj.sample_format = uint32(SegySampleFormat(spec.sample_format)); obj.trace_sorting_format = TraceSortingFormat(spec.trace_sorting_format); obj.sample_indexes = spec.sample_indexes / 1000.0; obj.crossline_indexes = uint32(spec.crossline_indexes); obj.inline_indexes = uint32(spec.inline_indexes); obj.offset_count = uint32(spec.offset_count); obj.first_trace_pos = uint32(spec.first_trace_pos); obj.il_stride = spec.il_stride; obj.xl_stride = spec.xl_stride; obj.trace_bsize = spec.trace_bsize; obj.t = obj.sample_indexes; obj.iline = obj.inline_indexes; obj.xline = obj.crossline_indexes; [~, s] = enumeration(obj.trace_sorting_format); obj.sorting = s{uint32(obj.trace_sorting_format) + 1}; end end end segyio-1.8.3/mex/segyutil.h0000664000372000037200000000175413407674361015255 0ustar travistravis#ifndef SEGYIO_SEGYUTIL_H #define SEGYIO_SEGYUTIL_H #include #include #include #include typedef struct { char* filename; int sample_format; int* crossline_indexes; int crossline_count; int* inline_indexes; int inline_count; int offset_count; float* sample_indices; int sample_count; int trace_sorting_format; int il_stride; int xl_stride; long first_trace_pos; int trace_bsize; } SegySpec; int segyCreateSpec(SegySpec* spec, const char* file, unsigned int inline_field, unsigned int crossline_field, float t0, float dt); void recreateSpec(SegySpec* spec, const mxArray* mex_spec); struct segy_file_format { int samples; long trace0; int trace_bsize; int traces; int format; }; struct segy_file_format buffmt( const char* ); struct segy_file_format filefmt( segy_file* ); segy_file* segyfopen( const mxArray* filename, const char* mode ); #endif //SEGYIO_SEGYUTIL_H segyio-1.8.3/mex/CMakeLists.txt0000664000372000037200000000453713407674361016001 0ustar travistravisproject(segyio-mex) if (NOT BUILD_MEX) unset(MATLAB_MCC CACHE) unset(MATLAB_MEX CACHE) unset(MATLAB_MEXEXT CACHE) unset(MATLAB_ROOT CACHE) unset(BUILD_MEX_TESTS CACHE) return() endif() include(matlab.cmake REQUIRED) option(BUILD_MEX_TESTS "Build matlab mex tests" ON) configure_file(Segy.m Segy.m) configure_file(SegySpec.m SegySpec.m) configure_file(SegySampleFormat.m SegySampleFormat.m) configure_file(TraceSortingFormat.m TraceSortingFormat.m) configure_file(TraceField.m TraceField.m) get_property(dirs TARGET segyio-shared PROPERTY INCLUDE_DIRECTORIES) include_directories(${dirs}) mexo(segyutil) mex(segyspec_mex) mex(segy_read_write_line_mex segyutil) mex(segy_read_write_ps_line_mex segyutil) mex(segy_get_header_mex segyutil) mex(segy_get_traces_mex segyutil) mex(segy_put_traces_mex segyutil) mex(segy_get_ntraces_mex segyutil) mex(segy_get_segy_header_mex segyutil) mex(segy_get_bfield_mex segyutil) mex(segy_get_trace_header_mex segyutil) mex(segy_get_field_mex segyutil) mex(segy_put_headers_mex segyutil) mex(segy_get_offsets_mex segyutil) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/segyspec_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_read_write_line_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_read_write_ps_line_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_get_header_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_get_traces_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_put_traces_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_get_ntraces_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_get_segy_header_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_get_bfield_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_get_trace_header_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_get_field_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_put_headers_mex.mexa64 ${CMAKE_CURRENT_BINARY_DIR}/segy_get_offsets_mex.mexa64 SegySpec.m Segy.m SegySampleFormat.m TraceSortingFormat.m TraceField.m DESTINATION ${CMAKE_INSTALL_PREFIX}/matlab) if(BUILD_MEX_TESTS) configure_file(${testdata}/small.sgy test/test-data/small.sgy COPYONLY) configure_file(${testdata}/small-ps.sgy test/test-data/small-ps.sgy COPYONLY) add_matlab_test(matlab.spec test/segyspec.m) add_matlab_test(matlab.segy test/segy.m) endif() segyio-1.8.3/mex/segy_put_traces_mex.c0000664000372000037200000000335313407674361017451 0ustar travistravis#include #include #include #include "segyutil.h" #include "matrix.h" #include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { char* msg1; char* msg2; int err; segy_file* fp = segyfopen( prhs[ 0 ], "r+b" ); plhs[ 0 ] = mxDuplicateArray( prhs[ 1 ] ); int first_trace = mxGetScalar( prhs[ 2 ] ); int last_trace = mxGetScalar( prhs[ 3 ] ); int notype = mxGetScalar( prhs[ 4 ] ); struct segy_file_format fmt = filefmt( fp ); if( notype != -1 ) fmt.format = notype; // if last_trace was defaulted we assign it to the last trace in the file if( last_trace == -1 ) last_trace = fmt.traces - 1; int traces = 1 + (last_trace - first_trace); long long bufsize = (long long)fmt.samples * traces; if( first_trace > last_trace ) { msg1 = "segy:get_traces:bounds"; msg2 = "first trace must be smaller than last trace"; goto cleanup; } float* out = mxGetData( plhs[ 0 ] ); segy_from_native( fmt.format, fmt.samples * fmt.traces, out ); float* itr = out; for( int i = first_trace; i <= last_trace; ++i ) { err = segy_writetrace( fp, i, itr, fmt.trace0, fmt.trace_bsize ); itr += fmt.samples; if( err != 0 ) { msg1 = "segy:put_traces:segy_writetrace"; msg2 = strerror( errno ); fmt.traces = i; goto cleanup; } } segy_close( fp ); segy_to_native( fmt.format, bufsize, out ); plhs[ 1 ] = mxCreateDoubleScalar( fmt.format ); return; cleanup: segy_close( fp ); segy_to_native( fmt.format, bufsize, out ); mexErrMsgIdAndTxt( msg1, msg2 ); } segyio-1.8.3/mex/matlab.cmake0000664000372000037200000002015613407674361015476 0ustar travistravis# This module looks for mex, the MATLAB compiler. # The following variables are defined when the script completes: # MATLAB_MEX: location of mex compiler # MATLAB_ROOT: root of MATLAB installation # MATLABMEX_FOUND: 0 if not found, 1 if found SET(MATLABMEX_FOUND 0) SET(MATLABMCC_FOUND 0) IF(WIN32) # Win32 is Untested # Taken from the older FindMatlab.cmake script as well as # the modifications by Ramon Casero and Tom Doel for Gerardus. # Search for a version of Matlab available, starting from the most modern one # to older versions. FOREACH(MATVER "7.20" "7.19" "7.18" "7.17" "7.16" "7.15" "7.14" "7.13" "7.12" "7.11" "7.10" "7.9" "7.8" "7.7" "7.6" "7.5" "7.4") IF((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL "") OR ("${MATLAB_ROOT}" STREQUAL "/registry")) GET_FILENAME_COMPONENT(MATLAB_ROOT "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${MATVER};MATLABROOT]" ABSOLUTE) SET(MATLAB_VERSION ${MATVER}) ENDIF((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL "") OR ("${MATLAB_ROOT}" STREQUAL "/registry")) ENDFOREACH(MATVER) FIND_PROGRAM(MATLAB_MEX mex ${MATLAB_ROOT}/bin ) FIND_PROGRAM(MATLAB_MCC mex ${MATLAB_ROOT}/bin ) ELSE(WIN32) # Check if this is a Mac. IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # Mac is untested # Taken from the older FindMatlab.cmake script as # well as the modifications by Ramon Casero and Tom Doel for Gerardus. SET(LIBRARY_EXTENSION .dylib) # If this is a Mac and the attempts to find MATLAB_ROOT have so far failed,~ # we look in the applications folder IF((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL "")) # Search for a version of Matlab available, starting from the most modern # one to older versions FOREACH(MATVER "2016b" "2014b" "R2013b" "R2013a" "R2012b" "R2012a" "R2011b" "R2011a" "R2010b" "R2010a" "R2009b" "R2009a" "R2008b") IF((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL "")) IF(EXISTS /Applications/MATLAB_${MATVER}.app) SET(MATLAB_ROOT /Applications/MATLAB_${MATVER}.app) ENDIF(EXISTS /Applications/MATLAB_${MATVER}.app) ENDIF((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL "")) ENDFOREACH(MATVER) ENDIF((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL "")) FIND_PROGRAM(MATLAB_MEX mex PATHS ${MATLAB_ROOT}/bin ) FIND_PROGRAM(MATLAB_MCC mcc PATHS ${MATLAB_ROOT}/bin ) ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # On a Linux system. The goal is to find MATLAB_ROOT. SET(LIBRARY_EXTENSION .so) FIND_PROGRAM(MATLAB_MEX mex PATHS ${MATLAB_ROOT}/bin /prog/matlab/R2016B/bin # Statoil location /prog/matlab/R2014B/bin # Statoil location /opt/matlab/bin /usr/local/matlab/bin $ENV{HOME}/matlab/bin # Now all the versions /opt/matlab/[rR]20[0-9][0-9][abAB]/bin /usr/local/matlab/[rR]20[0-9][0-9][abAB]/bin /opt/matlab-[rR]20[0-9][0-9][abAB]/bin /opt/matlab_[rR]20[0-9][0-9][abAB]/bin /usr/local/matlab-[rR]20[0-9][0-9][abAB]/bin /usr/local/matlab_[rR]20[0-9][0-9][abAB]/bin $ENV{HOME}/matlab/[rR]20[0-9][0-9][abAB]/bin $ENV{HOME}/matlab-[rR]20[0-9][0-9][abAB]/bin $ENV{HOME}/matlab_[rR]20[0-9][0-9][abAB]/bin ) GET_FILENAME_COMPONENT(MATLAB_MEX "${MATLAB_MEX}" REALPATH) GET_FILENAME_COMPONENT(MATLAB_BIN_ROOT "${MATLAB_MEX}" PATH) # Strip ./bin/. GET_FILENAME_COMPONENT(MATLAB_ROOT "${MATLAB_BIN_ROOT}" PATH) FIND_PROGRAM(MATLAB_MCC mcc PATHS ${MATLAB_ROOT}/bin ) FIND_PROGRAM(MATLAB_MEXEXT mexext PATHS ${MATLAB_ROOT}/bin ) GET_FILENAME_COMPONENT(MATLAB_MCC "${MATLAB_MCC}" REALPATH) GET_FILENAME_COMPONENT(MATLAB_MEXEXT "${MATLAB_MEXEXT}" REALPATH) ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") ENDIF(WIN32) IF(NOT EXISTS "${MATLAB_MEX}" AND "${MatlabMex_FIND_REQUIRED}") MESSAGE(FATAL_ERROR "Could not find MATLAB mex compiler; try specifying MATLAB_ROOT.") ELSE(NOT EXISTS "${MATLAB_MEX}" AND "${MatlabMex_FIND_REQUIRED}") IF(EXISTS "${MATLAB_MEX}") MESSAGE(STATUS "Found MATLAB mex compiler: ${MATLAB_MEX}") MESSAGE(STATUS "MATLAB root: ${MATLAB_ROOT}") SET(MATLABMEX_FOUND 1) ENDIF(EXISTS "${MATLAB_MEX}") ENDIF(NOT EXISTS "${MATLAB_MEX}" AND "${MatlabMex_FIND_REQUIRED}") IF(NOT EXISTS "${MATLAB_MCC}" AND "${MatlabMcc_FIND_REQUIRED}") MESSAGE(FATAL_ERROR "Could not find MATLAB mcc compiler; try specifying MATLAB_ROOT.") ELSE(NOT EXISTS "${MATLAB_MCC}" AND "${MatlabMcc_FIND_REQUIRED}") IF(EXISTS "${MATLAB_MCC}") MESSAGE(STATUS "Found MATLAB mcc compiler: ${MATLAB_MCC}") SET(MATLABMCC_FOUND 1) ENDIF(EXISTS "${MATLAB_MCC}") ENDIF(NOT EXISTS "${MATLAB_MCC}" AND "${MatlabMcc_FIND_REQUIRED}") MARK_AS_ADVANCED( MATLABMEX_FOUND ) SET(MATLAB_ROOT ${MATLAB_ROOT} CACHE FILEPATH "Path to a matlab installation") EXECUTE_PROCESS(COMMAND ${MATLAB_MEXEXT} OUTPUT_VARIABLE MEXEXT OUTPUT_STRIP_TRAILING_WHITESPACE) macro(mexo MEX_OBJECT) set(MEX_CFLAGS -fPIC -std=c99 -Werror) set(MEX_LDFLAGS) get_property(dirs DIRECTORY . PROPERTY INCLUDE_DIRECTORIES) foreach(dir ${dirs}) set(MEX_CFLAGS ${MEX_CFLAGS} -I${dir}) endforeach() set(MEX_LDFLAGS -shared) set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${MEX_OBJECT}.c) set(HEADER ${CMAKE_CURRENT_SOURCE_DIR}/${MEX_OBJECT}.h) set(OBJECT ${CMAKE_CURRENT_BINARY_DIR}/${MEX_OBJECT}.o) add_custom_command(OUTPUT ${OBJECT} COMMAND ${MATLAB_MEX} -c CC="${CMAKE_C_COMPILER}" LD="${CMAKE_CXX_COMPILER}" CFLAGS="${MEX_CFLAGS}" LDFLAGS="${MEX_LDFLAGS}" -outdir ${CMAKE_CURRENT_BINARY_DIR} ${SOURCE} DEPENDS ${SOURCE} ${HEADER} ) add_custom_target(${MEX_OBJECT} ALL DEPENDS ${OBJECT}) endmacro() macro(mex MEX_NAME ) set(DEP ${ARG2}) set(MEX_CFLAGS -fPIC -std=c99 -Werror) set(MEX_LDFLAGS) get_property(dirs DIRECTORY . PROPERTY INCLUDE_DIRECTORIES) foreach(dir ${dirs}) set(MEX_CFLAGS ${MEX_CFLAGS} -I${dir}) endforeach() set(MEX_LDFLAGS -shared) set(MEX_SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${MEX_NAME}.c) set(MEX_RESULT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${MEX_NAME}.${MEXEXT}) add_custom_command(OUTPUT ${MEX_RESULT_FILE} COMMAND ${MATLAB_MEX} CC="${CMAKE_C_COMPILER}" CXX="${CMAKE_CXX_COMPILER}" LD="${CMAKE_CXX_COMPILER}" CFLAGS="${MEX_CFLAGS}" LDFLAGS="${MEX_LDFLAGS}" ${OBJECT} $ -outdir ${CMAKE_CURRENT_BINARY_DIR} ${MEX_SOURCE_FILE} DEPENDS ${MEX_SOURCE_FILE} segyio segyutil.o ) add_custom_target(${MEX_NAME} ALL DEPENDS ${MEX_RESULT_FILE} segyutil.o) set(${MEX_NAME}_TARGET ${MEX_NAME} PARENT_SCOPE) set(${MEX_NAME}_FILE ${MEX_RESULT_FILE} PARENT_SCOPE) endmacro() # this isn't meant to be run directly; use matlab_add_test or # matlab_add_example instead function(matlab_test TYPE TESTNAME MCC_SOURCE_FILE) configure_file(${MCC_SOURCE_FILE} ${MCC_SOURCE_FILE} COPYONLY) add_test(NAME ${TESTNAME} COMMAND ${MATLAB_ROOT}/bin/matlab -nodisplay -nosplash -nodesktop -r "addpath('../mex'), try, run('${MCC_SOURCE_FILE}'), exit(0), catch, exit(-1), end;" < /dev/null ) endfunction() function(add_matlab_test TESTNAME MCC_SOURCE_FILE) matlab_test(tests ${TESTNAME} ${MCC_SOURCE_FILE}) endfunction() # add_matlab_example takes an arbitrary number of arguments which it will # forward to the example program function(add_matlab_example TESTNAME MCC_SOURCE_FILE) matlab_test(examples ${TESTNAME} ${MCC_SOURCE_FILE}) endfunction() segyio-1.8.3/mex/segy_get_ps_line_mex.c0000664000372000037200000000304213407674361017563 0ustar travistravis#include #include "mex.h" #include "matrix.h" #include "segyutil.h" #include void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int errc = 0; if (nrhs != 4) { goto ERROR; } const mxArray* mx_spec = prhs[0]; const mxArray* mx_offset = prhs[1]; const mxArray* mx_il_word = prhs[2]; const mxArray* mx_xl_word = prhs[3]; SegySpec spec; recreateSpec(&spec, mx_spec); int offset = (int)mxGetScalar(mx_offset); int il = (int)mxGetScalar(mx_il_word); int xl = (int)mxGetScalar(mx_xl_word); segy_file* fp = segyio_open( spec.filename, "rb" ); if( !fp ) { errc = SEGY_FOPEN_ERROR; goto ERROR; }; plhs[0] = mxCreateNumericMatrix(spec.sample_count, spec.offset_count, mxINT32_CLASS, mxREAL); int* int_offsets = mxMalloc(sizeof( int ) * spec.offset_count); errc = segy_offsets(fp, offset, spec.offset_count, int_offsets, spec.first_trace_pos, spec.trace_bsize); if( err != SEGY_OK ) goto CLEANUP; int32_t* plhs0 = (int32_t*)mxGetScalar(plhs[0]); for( int i = 0; i < spec.sample_count; ++i ) plhs0[i] = int_offsets[i]; segy_close(fp); return; CLEANUP: segy_close(fp); ERROR: { int nfields = 1; const char *fnames[nfields]; fnames[0] = "error"; plhs[0] = mxCreateStructMatrix(0,0, nfields, fnames); mxSetFieldByNumber(plhs[0], 0, 0, mxCreateDoubleScalar(errc)); } } segyio-1.8.3/mex/segy_read_write_ps_line_mex.c0000664000372000037200000000752713407674361021145 0ustar travistravis#include #include "mex.h" #include "matrix.h" #include "segyutil.h" #include /* The gateway function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { if( nrhs < 5 || nrhs > 6 ) goto ERROR; bool read = nrhs == 5; const mxArray* mx_spec = prhs[0]; const mxArray* mx_index = prhs[1]; const mxArray* mx_line_length = prhs[2]; const mxArray* mx_line_indexes = prhs[3]; const mxArray* mx_stride = prhs[4]; SegySpec spec; recreateSpec(&spec, mx_spec); size_t index = (size_t)mxGetScalar(mx_index); uint32_t line_length = (uint32_t)mxGetScalar(mx_line_length); uint32_t* line_indexes = (uint32_t*)mxGetData(mx_line_indexes); int n = mxGetN(mx_line_indexes); int m = mxGetM(mx_line_indexes); uint32_t line_count = (n>m)? n:m; uint32_t stride = (uint32_t)mxGetScalar(mx_stride); int offsets = spec.offset_count; segy_file* fp; int line_trace0; int errc = segy_line_trace0( index, line_length, stride, offsets, line_indexes, line_count, &line_trace0 ); if( errc != SEGY_OK ) { mexErrMsgIdAndTxt( "segy:get_ps_line:wrong_line_number", "Specified line number is not in cube." ); return; } const char* mode = read ? "rb" : "r+b"; fp = segy_open( spec.filename, mode ); if( !fp ) { mexErrMsgIdAndTxt( "segy:get:ps_line:file", "unable to open file" ); return; } mwSize dims[] = { spec.sample_count, spec.offset_count, line_length }; const size_t tr_size = SEGY_TRACE_HEADER_SIZE + spec.trace_bsize; if( read ) { plhs[0] = mxCreateNumericArray(3, dims, mxSINGLE_CLASS, mxREAL ); float* buf = (float*) mxGetData(plhs[0]); for( int i = 0; i < offsets; ++i ) { errc = segy_read_line( fp, line_trace0, line_length, stride, offsets, buf + (spec.sample_count * line_length * i), spec.first_trace_pos + (i * tr_size), spec.trace_bsize ); if( errc != 0 ) goto CLEANUP; } errc = segy_to_native( spec.sample_format, offsets * line_length * spec.sample_count, buf ); if( errc != 0 ) goto CLEANUP; } else { const mxArray* mx_data = prhs[5]; float* buf = (float*) mxGetData(mx_data); errc = segy_from_native( spec.sample_format, offsets * line_length * spec.sample_count, buf ); if( errc != 0 ) goto CLEANUP; for( int i = 0; i < offsets; ++i ) { errc = segy_write_line( fp, line_trace0, line_length, stride, offsets, buf + (spec.sample_count * line_length * i), spec.first_trace_pos + (i * tr_size), spec.trace_bsize ); if( errc != 0 ) goto CLEANUP; } errc = segy_to_native( spec.sample_format, offsets * line_length * spec.sample_count, buf ); if( errc != 0 ) goto CLEANUP; } segy_close(fp); return; CLEANUP: segy_close(fp); ERROR: { int nfields = 1; const char *fnames[nfields]; fnames[0] = "error"; plhs[0] = mxCreateStructMatrix(0,0, nfields, fnames); mxSetFieldByNumber(plhs[0], 0, 0, mxCreateDoubleScalar(errc)); } } segyio-1.8.3/mex/segy_get_segy_header_mex.c0000664000372000037200000000172713407674361020421 0ustar travistravis#include #include #include #include "segyutil.h" #include "matrix.h" #include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { char* msg1; char* msg2; int err; segy_file* fp = segyfopen( prhs[ 0 ], "rb" ); char* textheader = mxMalloc( segy_textheader_size() ); err = segy_read_textheader( fp, textheader ); if( err != 0 ) { msg1 = "segy:text_header:os"; msg2 = strerror( errno ); goto cleanup; } plhs[ 0 ] = mxCreateString( textheader ); mwSize dims[ 1 ] = { segy_binheader_size() }; plhs[ 1 ] = mxCreateCharArray( 1, dims ); err = segy_binheader( fp, mxGetData( plhs[ 1 ] ) ); if( err != 0 ) { msg1 = "segy:binary_header:os"; msg2 = strerror( errno ); goto cleanup; } mxFree( textheader ); return; cleanup: segy_close( fp ); mexErrMsgIdAndTxt( msg1, msg2 ); } segyio-1.8.3/mex/test/0000775000372000037200000000000013407674361014207 5ustar travistravissegyio-1.8.3/mex/test/segyspec.m0000664000372000037200000000461313407674361016213 0ustar travistravis% test segyspec % preconditions filename = 'test-data/small.sgy'; assert(exist(filename,'file')==2); t0 = 1111.0; %% no such file no_such_filename = 'no-such-dir/no-such-file.sgy'; assert(exist(no_such_filename,'file')~=2); try spec = SegySpec(no_such_filename, TraceField.Inline3D, TraceField.Crossline3D, t0); %should not reach here assert(false); catch %not actually needed... assert(true); end %% Spec is created try spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); catch %nothing should be caught assert(false); end %% IBM_FLOAT_4_BYTE spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); assert(spec.sample_format == SegySampleFormat.IBM_FLOAT_4_BYTE); %% filename is set spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); assert(strcmp(spec.filename,filename)); %% trace_sorting_format spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); assert(spec.trace_sorting_format == TraceSortingFormat.iline); %%offset_count spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); assert(length(spec.offset_count) == 1); %% sample_indexes spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); sample_indexes = spec.sample_indexes; assert(length(sample_indexes) == 50); for i = 1:length(sample_indexes) t = t0 + (i-1) * 4; assert(sample_indexes(i) == t); end %% first_trace_pos spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); first_trace_pos = spec.first_trace_pos; assert(first_trace_pos == 3600); %% il_stride spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); il_stride = spec.il_stride; assert(il_stride == 1); %% xl_stride spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); xl_stride = spec.xl_stride; assert(xl_stride == 5); %% xl_stride spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); trace_bsize = spec.trace_bsize; assert(trace_bsize == 50*4); %% xline spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); assert(length(spec.crossline_indexes)==5) for xl = spec.crossline_indexes' assert(xl >= 20 && xl <= 24); end %% iline spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0); assert(length(spec.inline_indexes)==5) for il = spec.inline_indexes' assert(il >= 1 && il <= 5); end segyio-1.8.3/mex/test/segy.m0000664000372000037200000001737313407674361015347 0ustar travistravis% test segyline % preconditions filename = 'test-data/small.sgy'; assert(exist(filename,'file')==2); t0 = 1111.0; %% Spec is created try spec = Segy.interpret_segycube(filename, 'Inline3D', 'Crossline3D', t0); spec = Segy.interpret_segycube(filename, TraceField.Inline3D, 'Crossline3D', t0); spec = Segy.interpret_segycube(filename, TraceField.Inline3D, 193, t0); data = Segy.get_cube( spec ); assert(all(size(data) == [50, 5, 5])); catch %nothing should be caught assert(false); end % fail when file doesn't exist try Segy.get_header('does-not-exist', 193); assert(false); catch assert(true); end try Segy.get_traces('does-not-exist', 189, 193 ); assert(false); catch assert(true); end try Segy.get_ntraces('does-not-exist'); assert(false); catch assert(true); end try Segy.interpret_segycube('does-not-exist'); assert(false); catch assert(true); end %% Segy.readInLine 4 spec = Segy.interpret_segycube(filename, 'Inline3D', 'Crossline3D', t0); data = Segy.get_line(spec, 'iline', 4); sample_count = length(spec.sample_indexes); eps = 1e-6; % first trace along xline % first sample assert(abs(data(1, 1) - 4.2) #include #include #include "segyutil.h" #include "matrix.h" #include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { const char* bin = mxGetData( prhs[ 0 ] ); const int field = mxGetScalar( prhs[ 1 ] ); int f; int err = segy_get_field( bin, field, &f ); if( err == SEGY_INVALID_FIELD ) mexErrMsgIdAndTxt( "segy:get_field:invalid_field", "Invalid field value/header offset" ); plhs[ 0 ] = mxCreateDoubleScalar( f ); } segyio-1.8.3/mex/segy_get_bfield_mex.c0000664000372000037200000000111313407674361017354 0ustar travistravis#include #include #include #include "segyutil.h" #include "matrix.h" #include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { const char* bin = mxGetData( prhs[ 0 ] ); const int field = mxGetScalar( prhs[ 1 ] ); int f; int err = segy_get_bfield( bin, field, &f ); if( err == SEGY_INVALID_FIELD ) mexErrMsgIdAndTxt( "segy:get_bfield:invalid_field", "Invalid field value/header offset" ); plhs[ 0 ] = mxCreateDoubleScalar( f ); } segyio-1.8.3/.travis.yml0000664000372000037200000001510513407674361014552 0ustar travistravislanguage: python python: - 2.7 - 3.4 - 3.5 - 3.6 env: global: - UNICODE_WIDTH=32 - PLAT=x86_64 - MB_PYTHON_VERSION=$TRAVIS_PYTHON_VERSION - VERSION=$(echo $TRAVIS_TAG | sed s/v//) os: - linux services: docker sudo: required matrix: fast_finish: true include: - python: 3.7 dist: xenial sudo: true - compiler: clang python: 3.7 dist: xenial env: - SCAN="scan-build --status-bugs" - SOURCEDEPLOY=1 - MKDOC="-DBUILD_DOC=ON -DSPHINX_ARGS=-WT" - os: osx language: generic env: MB_PYTHON_VERSION=2.7 python: 2.7 - os: osx language: generic env: MB_PYTHON_VERSION=3.4 python: 3.4 - os: osx language: generic env: MB_PYTHON_VERSION=3.5 python: 3.5 - os: osx language: generic env: MB_PYTHON_VERSION=3.6 python: 3.6 - os: osx language: generic env: MB_PYTHON_VERSION=3.7 python: 3.7 addons: apt: sources: - sourceline: 'ppa:jokva/backports' - george-edison55-precise-backports # cmake 3 packages: - cppcheck - cmake - cmake-data before_install: - unset -f pushd - unset -f popd - source multibuild/common_utils.sh - source multibuild/travis_steps.sh - before_install install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew install cppcheck; fi - pip install -r requirements.txt - pip install bandit setuptools setuptools-scm pytest pytest-runner sphinx before_script: - enabled="-DBUILD_PYTHON=OFF -DBUILD_MEX=OFF" - if [[ -n "${MB_PYTHON_VERSION+1}" ]]; then enabled="$enabled -DBUILD_PYTHON=ON -DREQUIRE_PYTHON=ON"; fi - bandit -c bandit.yml -r python - cmake --version - mkdir build - pushd build - $SCAN cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_NAME_DIR=/usr/local/lib $MKDOC $enabled .. - cppcheck --enable=style,portability,performance,warning --library=posix --library=$TRAVIS_BUILD_DIR/cppcheck/segyio.cfg --suppressions-list=$TRAVIS_BUILD_DIR/cppcheck/suppressions.txt --inline-suppr --project=compile_commands.json --error-exitcode=1 - popd # distutils/setuptools on macos ignores the --rpath argument, so set # DYLD_LIBRARY_PATH so that the freshly-built image is picked up on for the # tests. # # segyio is configured with CMAKE_INSTALL_NAME_DIR so that the wheel build on # OS X so the delocate tool can figure out what dylib to include. script: - pushd build - export DYLD_LIBRARY_PATH=$PWD/lib - $SCAN make && ctest --output-on-failure - sudo make install - popd - build_wheel . $PLAT - install_run $PLAT - mv wheelhouse dist before_deploy: # OS X ships with a tar that doesn't support --exclude-vcs, which is # unproblematic as long as source code is uploaded from linux. # # when doing source deploy, remove the dist directory with pre-built wheels, # otherwise they get picked up instead, which will surely fail because the # wheel has already been uploaded to pypi. - if [[ "$TRAVIS_OS_NAME" == "linux" && ! -d segyio-$VERSION ]]; then git clone $TRAVIS_BUILD_DIR segyio-$VERSION; echo "version = '$TRAVIS_TAG'" > segyio-$VERSION/python/segyio/version.py; tar --exclude-vcs -C $TRAVIS_BUILD_DIR -czvf segyio-$VERSION.tar.gz segyio-$VERSION; zip --exclude *.git -r segyio-$VERSION.zip $TRAVIS_BUILD_DIR/segyio-$VERSION/*; fi - if [[ $SOURCEDEPLOY ]]; then rm -rf dist; fi deploy: - provider: pypi # source distribution (done from linux python 3.6 only) skip_cleanup: true skip_upload_docs: true user: statoil-travis password: secure: WHeA5x2iiXzjYXdgZeJU6l4fawRi/umqH1713QAj0RPZBAnD+9m8Zrpn2UWn9+1dtx6xUMkNg3ZTueVKTKo0f2i/4o0xkzQ5BW11cetCWusV2Dku1btPTA5Fhs+dvPDlL3m496a3Bq/A/fRDj5JLDiiPibvpM01lEBxFKYooWGQ75HVuhnAt57vabD45gDpIE7N23+So4+9bsG/nT/ZlgoaS01uLTdlnf6tjNgP0/UBkonmedC62iVvCu7itfHZMTY2rSeww7KBMI3s7Gz+cyx9IbI3shbDpdJGHpM8Qe+1oFi31Z+DylWQA5SkpHlLMUP+zjMKLF+1hXGNUeJuyadIFrxzbS3vTV2yRPa6ol8q+bX7YLy0xNLSE8aMm54LKgXfRKLc3G8d3I33oEfyk5hygY8iEX728r2TsARslYxOF3sZqJvY8lx4GBEDiXxX2GJvGCPy/Uby786uWnZlFFkDERk3nawE0W68zY0GElbutq6HMSk6v49J7em9Rg/QLptjoa0uF2A9Cy+BAJcnfauIawOG3UPXZ8kD60PTbu8tqtwtXO5lzTSIOr1lt3+6R8GmCc2hz2YXELKvdnZWYCXAjnNuC4eESlp7zxmzhpOVkb2Jy1v6rGKpcxVMggLQbOjOGWPLg9q4+OZQBw5bhMGmVGQhSBuxzEb/wBRy9XV8= on: condition: $SOURCEDEPLOY tags: true - provider: pypi # upload built wheels skip_cleanup: true skip_upload_docs: true user: statoil-travis distributions: build password: secure: WHeA5x2iiXzjYXdgZeJU6l4fawRi/umqH1713QAj0RPZBAnD+9m8Zrpn2UWn9+1dtx6xUMkNg3ZTueVKTKo0f2i/4o0xkzQ5BW11cetCWusV2Dku1btPTA5Fhs+dvPDlL3m496a3Bq/A/fRDj5JLDiiPibvpM01lEBxFKYooWGQ75HVuhnAt57vabD45gDpIE7N23+So4+9bsG/nT/ZlgoaS01uLTdlnf6tjNgP0/UBkonmedC62iVvCu7itfHZMTY2rSeww7KBMI3s7Gz+cyx9IbI3shbDpdJGHpM8Qe+1oFi31Z+DylWQA5SkpHlLMUP+zjMKLF+1hXGNUeJuyadIFrxzbS3vTV2yRPa6ol8q+bX7YLy0xNLSE8aMm54LKgXfRKLc3G8d3I33oEfyk5hygY8iEX728r2TsARslYxOF3sZqJvY8lx4GBEDiXxX2GJvGCPy/Uby786uWnZlFFkDERk3nawE0W68zY0GElbutq6HMSk6v49J7em9Rg/QLptjoa0uF2A9Cy+BAJcnfauIawOG3UPXZ8kD60PTbu8tqtwtXO5lzTSIOr1lt3+6R8GmCc2hz2YXELKvdnZWYCXAjnNuC4eESlp7zxmzhpOVkb2Jy1v6rGKpcxVMggLQbOjOGWPLg9q4+OZQBw5bhMGmVGQhSBuxzEb/wBRy9XV8= on: condition: -z $SOURCEDEPLOY tags: true - provider: releases # upload tarball and zip with source code skip_cleanup: true overwrite: true file: - $TRAVIS_BUILD_DIR/segyio-$VERSION.tar.gz - $TRAVIS_BUILD_DIR/segyio-$VERSION.zip api_key: secure: VdV/5kCCwUFwgU7wvKRrOy4u9nnvLsM3RoW1G2z8w8e838fcTeXLU3Zu8rLzLpcaXJKX07WNQmG85PZrgRjB9mzZAbXnPJeMk5MT3YVWaiyF6zNxK+mQQOvTCJ8P25nm5Iq1PLtIW/wM1RqNLgT8t3AsLiIva+6JK+2wGA2ilOl2YVgJqEiZV1f9DJutPewDf8pqYrnrHktMmkio/uubc12MLFOrNeQxK/EJahw7x56q8EcxrJXHnv6T2zEvUdcEYfRvIrT62jiVqiJP9wmUVdq2x8/RlgRzcCpGhy2o17iMUIH228so2hbu5/NcvtAh/LUDeqlhQ1YLRp1vO6H8Uh9B6aJgBNPwYmrKBHQQD27l5vt74DNJuqsXTZtrQlzUiiptKTV7mjFckF7mG04d1J/0GcVcxjpRZa3rp85KymQKWTsuWJYrCWSeVh+SMwUAbMZ3/vhEKPtrf4rwI+4INTitLuBNfcyH0W+W/rWLBMYoojRW0NJjc+4HJGpkMPbFkDjpde31ZqgI/Cec0GPpqbtsb3DkK/f4mLrR+F59b3+Lj0Cjyh9lM2fVXTrPYt13kdwbtBnNy6x2kdTkEBCk9m+eTFAfJGal+3SwgLeiGQdkjdZ7vSLwwdRf7Qvz5WjxKQ+feFWm+qi0GurWOEaZrubB82CGukxOXKzrvAGN3Eo= on: tags: true condition: $SOURCEDEPLOY segyio-1.8.3/external/0000775000372000037200000000000013407674361014261 5ustar travistravissegyio-1.8.3/external/catch2/0000775000372000037200000000000013407674361015425 5ustar travistravissegyio-1.8.3/external/catch2/dummy.cpp0000664000372000037200000000000013407674361017252 0ustar travistravissegyio-1.8.3/external/catch2/catch/0000775000372000037200000000000013407674361016507 5ustar travistravissegyio-1.8.3/external/catch2/catch/catch.hpp0000664000372000037200000156114413407674361020316 0ustar travistravis/* * Catch v2.2.3 * Generated: 2018-06-06 23:11:57.601416 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED // start catch.hpp #define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MINOR 2 #define CATCH_VERSION_PATCH 3 #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ # pragma GCC system_header #endif // start catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC # pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wparentheses" # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" #endif // end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL # define CATCH_CONFIG_ALL_PARTS #endif // In the impl file, we want to have access to all parts of the headers // Can also be used to sanely support PCHs #if defined(CATCH_CONFIG_ALL_PARTS) # define CATCH_CONFIG_EXTERNAL_INTERFACES # if defined(CATCH_CONFIG_DISABLE_MATCHERS) # undef CATCH_CONFIG_DISABLE_MATCHERS # endif # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER #endif #if !defined(CATCH_CONFIG_IMPL_ONLY) // start catch_platform.h #ifdef __APPLE__ # include # if TARGET_OS_OSX == 1 # define CATCH_PLATFORM_MAC # elif TARGET_OS_IPHONE == 1 # define CATCH_PLATFORM_IPHONE # endif #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) # define CATCH_PLATFORM_WINDOWS #endif // end catch_platform.h #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED # define CLARA_CONFIG_MAIN # endif #endif // start catch_user_interfaces.h namespace Catch { unsigned int rngSeed(); } // end catch_user_interfaces.h // start catch_tag_alias_autoregistrar.h // start catch_common.h // start catch_compiler_capabilities.h // Detect a number of compiler features - by compiler // The following features are defined: // // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too // **************** // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. #ifdef __cplusplus # if __cplusplus >= 201402L # define CATCH_CPP14_OR_GREATER # endif # if __cplusplus >= 201703L # define CATCH_CPP17_OR_GREATER # endif #endif #if defined(CATCH_CPP17_OR_GREATER) # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS #endif #ifdef __clang__ # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ _Pragma( "clang diagnostic push" ) \ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ _Pragma( "clang diagnostic pop" ) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic push" ) \ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic pop" ) #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // Assume that non-Windows platforms support posix signals by default #if !defined(CATCH_PLATFORM_WINDOWS) #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS #endif //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals #if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS # define CATCH_CONFIG_COLOUR_NONE #endif //////////////////////////////////////////////////////////////////////////////// // Android somehow still does not support std::to_string #if defined(__ANDROID__) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING #endif //////////////////////////////////////////////////////////////////////////////// // Not all Windows environments support SEH properly #if defined(__MINGW32__) # define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #endif //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #ifdef _MSC_VER # if _MSC_VER >= 1900 // Visual Studio 2015 or newer # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS # endif // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) # define CATCH_CONFIG_COLOUR_NONE # else # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // DJGPP #ifdef __DJGPP__ # define CATCH_INTERNAL_CONFIG_NO_WCHAR #endif // __DJGPP__ //////////////////////////////////////////////////////////////////////////////// // Use of __COUNTER__ is suppressed during code analysis in // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly // handled by it. // Otherwise all supported compilers support COUNTER macro, // but user still might want to turn it off #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. #if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif // This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. #if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) # define CATCH_CONFIG_WCHAR #endif #if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) # define CATCH_CONFIG_CPP11_TO_STRING #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif // end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) #else # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif #include #include #include namespace Catch { struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; protected: NonCopyable(); virtual ~NonCopyable(); }; struct SourceLineInfo { SourceLineInfo() = delete; SourceLineInfo( char const* _file, std::size_t _line ) noexcept : file( _file ), line( _line ) {} SourceLineInfo( SourceLineInfo const& other ) = default; SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; bool empty() const noexcept; bool operator == ( SourceLineInfo const& other ) const noexcept; bool operator < ( SourceLineInfo const& other ) const noexcept; char const* file; std::size_t line; }; std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { std::string operator+() const; }; template T const& operator + ( T const& value, StreamEndStop ) { return value; } } #define CATCH_INTERNAL_LINEINFO \ ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) // end catch_common.h namespace Catch { struct RegistrarForTagAliases { RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h // start catch_interfaces_testcase.h #include #include namespace Catch { class TestSpec; struct ITestInvoker { virtual void invoke () const = 0; virtual ~ITestInvoker(); }; using ITestCasePtr = std::shared_ptr; class TestCase; struct IConfig; struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); } // end catch_interfaces_testcase.h // start catch_stringref.h #include #include #include namespace Catch { class StringData; /// A non-owning string class (similar to the forthcoming std::string_view) /// Note that, because a StringRef may be a substring of another string, /// it may not be null terminated. c_str() must return a null terminated /// string, however, and so the StringRef will internally take ownership /// (taking a copy), if necessary. In theory this ownership is not externally /// visible - but it does mean (substring) StringRefs should not be shared between /// threads. class StringRef { public: using size_type = std::size_t; private: friend struct StringRefTestAccess; char const* m_start; size_type m_size; char* m_data = nullptr; void takeOwnership(); static constexpr char const* const s_empty = ""; public: // construction/ assignment StringRef() noexcept : StringRef( s_empty, 0 ) {} StringRef( StringRef const& other ) noexcept : m_start( other.m_start ), m_size( other.m_size ) {} StringRef( StringRef&& other ) noexcept : m_start( other.m_start ), m_size( other.m_size ), m_data( other.m_data ) { other.m_data = nullptr; } StringRef( char const* rawChars ) noexcept; StringRef( char const* rawChars, size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} StringRef( std::string const& stdString ) noexcept : m_start( stdString.c_str() ), m_size( stdString.size() ) {} ~StringRef() noexcept { delete[] m_data; } auto operator = ( StringRef const &other ) noexcept -> StringRef& { delete[] m_data; m_data = nullptr; m_start = other.m_start; m_size = other.m_size; return *this; } operator std::string() const; void swap( StringRef& other ) noexcept; public: // operators auto operator == ( StringRef const& other ) const noexcept -> bool; auto operator != ( StringRef const& other ) const noexcept -> bool; auto operator[] ( size_type index ) const noexcept -> char; public: // named queries auto empty() const noexcept -> bool { return m_size == 0; } auto size() const noexcept -> size_type { return m_size; } auto numberOfCharacters() const noexcept -> size_type; auto c_str() const -> char const*; public: // substrings and searches auto substr( size_type start, size_type size ) const noexcept -> StringRef; // Returns the current start pointer. // Note that the pointer can change when if the StringRef is a substring auto currentData() const noexcept -> char const*; private: // ownership queries - may not be consistent between calls auto isOwned() const noexcept -> bool; auto isSubstring() const noexcept -> bool; }; auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } } // namespace Catch // end catch_stringref.h namespace Catch { template class TestInvokerAsMethod : public ITestInvoker { void (C::*m_testAsMethod)(); public: TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} void invoke() const override { C obj; (obj.*m_testAsMethod)(); } }; auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; template auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { return new(std::nothrow) TestInvokerAsMethod( testAsMethod ); } struct NameAndTags { NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; StringRef name; StringRef tags; }; struct AutoReg : NonCopyable { AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; ~AutoReg(); }; } // end namespace Catch #define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) #define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF #if defined(CATCH_CONFIG_DISABLE) #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ static void TestName() #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ namespace{ \ struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ void test(); \ }; \ } \ void TestName::test() #endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ \ struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ } \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS // end catch_test_registry.h // start catch_capture.hpp // start catch_assertionhandler.h // start catch_assertioninfo.h // start catch_result_type.h namespace Catch { // ResultWas::OfType enum struct ResultWas { enum OfType { Unknown = -1, Ok = 0, Info = 1, Warning = 2, FailureBit = 0x10, ExpressionFailed = FailureBit | 1, ExplicitFailure = FailureBit | 2, Exception = 0x100 | FailureBit, ThrewException = Exception | 1, DidntThrowException = Exception | 2, FatalErrorCondition = 0x200 | FailureBit }; }; bool isOk( ResultWas::OfType resultType ); bool isJustInfo( int flags ); // ResultDisposition::Flags enum struct ResultDisposition { enum Flags { Normal = 0x01, ContinueOnFailure = 0x02, // Failures fail test, but execution continues FalseTest = 0x04, // Prefix expression with ! SuppressFail = 0x08 // Failures are reported but do not fail the test }; }; ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); bool shouldContinueOnFailure( int flags ); inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } bool shouldSuppressFailure( int flags ); } // end namespace Catch // end catch_result_type.h namespace Catch { struct AssertionInfo { StringRef macroName; SourceLineInfo lineInfo; StringRef capturedExpression; ResultDisposition::Flags resultDisposition; // We want to delete this constructor but a compiler bug in 4.8 means // the struct is then treated as non-aggregate //AssertionInfo() = delete; }; } // end namespace Catch // end catch_assertioninfo.h // start catch_decomposer.h // start catch_tostring.h #include #include #include #include // start catch_stream.h #include #include #include namespace Catch { std::ostream& cout(); std::ostream& cerr(); std::ostream& clog(); class StringRef; struct IStream { virtual ~IStream(); virtual std::ostream& stream() const = 0; }; auto makeStream( StringRef const &filename ) -> IStream const*; class ReusableStringStream { std::size_t m_index; std::ostream* m_oss; public: ReusableStringStream(); ~ReusableStringStream(); auto str() const -> std::string; template auto operator << ( T const& value ) -> ReusableStringStream& { *m_oss << value; return *this; } auto get() -> std::ostream& { return *m_oss; } static void cleanup(); }; } // end catch_stream.h #ifdef __OBJC__ // start catch_objc_arc.hpp #import #ifdef __has_feature #define CATCH_ARC_ENABLED __has_feature(objc_arc) #else #define CATCH_ARC_ENABLED 0 #endif void arcSafeRelease( NSObject* obj ); id performOptionalSelector( id obj, SEL sel ); #if !CATCH_ARC_ENABLED inline void arcSafeRelease( NSObject* obj ) { [obj release]; } inline id performOptionalSelector( id obj, SEL sel ) { if( [obj respondsToSelector: sel] ) return [obj performSelector: sel]; return nil; } #define CATCH_UNSAFE_UNRETAINED #define CATCH_ARC_STRONG #else inline void arcSafeRelease( NSObject* ){} inline id performOptionalSelector( id obj, SEL sel ) { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" #endif if( [obj respondsToSelector: sel] ) return [obj performSelector: sel]; #ifdef __clang__ #pragma clang diagnostic pop #endif return nil; } #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained #define CATCH_ARC_STRONG __strong #endif // end catch_objc_arc.hpp #endif #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless #endif // We need a dummy global operator<< so we can bring it into Catch namespace later struct Catch_global_namespace_dummy {}; std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { // Bring in operator<< from global namespace into Catch namespace using ::operator<<; namespace Detail { extern const std::string unprintableString; std::string rawMemoryToString( const void *object, std::size_t size ); template std::string rawMemoryToString( const T& object ) { return rawMemoryToString( &object, sizeof(object) ); } template class IsStreamInsertable { template static auto test(int) -> decltype(std::declval() << std::declval(), std::true_type()); template static auto test(...)->std::false_type; public: static const bool value = decltype(test(0))::value; }; template std::string convertUnknownEnumToString( E e ); template typename std::enable_if< !std::is_enum::value && !std::is_base_of::value, std::string>::type convertUnstreamable( T const& ) { return Detail::unprintableString; } template typename std::enable_if< !std::is_enum::value && std::is_base_of::value, std::string>::type convertUnstreamable(T const& ex) { return ex.what(); } template typename std::enable_if< std::is_enum::value , std::string>::type convertUnstreamable( T const& value ) { return convertUnknownEnumToString( value ); } #if defined(_MANAGED) //! Convert a CLR string to a utf8 std::string template std::string clrReferenceToString( T^ ref ) { if (ref == nullptr) return std::string("null"); auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); cli::pin_ptr p = &bytes[0]; return std::string(reinterpret_cast(p), bytes->Length); } #endif } // namespace Detail // If we decide for C++14, change these to enable_if_ts template struct StringMaker { template static typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type convert(const Fake& value) { ReusableStringStream rss; // NB: call using the function-like syntax to avoid ambiguity with // user-defined templated operator<< under clang. rss.operator<<(value); return rss.str(); } template static typename std::enable_if::value, std::string>::type convert( const Fake& value ) { #if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) return Detail::convertUnstreamable(value); #else return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); #endif } }; namespace Detail { // This function dispatches all stringification requests inside of Catch. // Should be preferably called fully qualified, like ::Catch::Detail::stringify template std::string stringify(const T& e) { return ::Catch::StringMaker::type>::type>::convert(e); } template std::string convertUnknownEnumToString( E e ) { return ::Catch::Detail::stringify(static_cast::type>(e)); } #if defined(_MANAGED) template std::string stringify( T^ e ) { return ::Catch::StringMaker::convert(e); } #endif } // namespace Detail // Some predefined specializations template<> struct StringMaker { static std::string convert(const std::string& str); }; #ifdef CATCH_CONFIG_WCHAR template<> struct StringMaker { static std::string convert(const std::wstring& wstr); }; #endif template<> struct StringMaker { static std::string convert(char const * str); }; template<> struct StringMaker { static std::string convert(char * str); }; #ifdef CATCH_CONFIG_WCHAR template<> struct StringMaker { static std::string convert(wchar_t const * str); }; template<> struct StringMaker { static std::string convert(wchar_t * str); }; #endif // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, // while keeping string semantics? template struct StringMaker { static std::string convert(char const* str) { return ::Catch::Detail::stringify(std::string{ str }); } }; template struct StringMaker { static std::string convert(signed char const* str) { return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); } }; template struct StringMaker { static std::string convert(unsigned char const* str) { return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); } }; template<> struct StringMaker { static std::string convert(int value); }; template<> struct StringMaker { static std::string convert(long value); }; template<> struct StringMaker { static std::string convert(long long value); }; template<> struct StringMaker { static std::string convert(unsigned int value); }; template<> struct StringMaker { static std::string convert(unsigned long value); }; template<> struct StringMaker { static std::string convert(unsigned long long value); }; template<> struct StringMaker { static std::string convert(bool b); }; template<> struct StringMaker { static std::string convert(char c); }; template<> struct StringMaker { static std::string convert(signed char c); }; template<> struct StringMaker { static std::string convert(unsigned char c); }; template<> struct StringMaker { static std::string convert(std::nullptr_t); }; template<> struct StringMaker { static std::string convert(float value); }; template<> struct StringMaker { static std::string convert(double value); }; template struct StringMaker { template static std::string convert(U* p) { if (p) { return ::Catch::Detail::rawMemoryToString(p); } else { return "nullptr"; } } }; template struct StringMaker { static std::string convert(R C::* p) { if (p) { return ::Catch::Detail::rawMemoryToString(p); } else { return "nullptr"; } } }; #if defined(_MANAGED) template struct StringMaker { static std::string convert( T^ ref ) { return ::Catch::Detail::clrReferenceToString(ref); } }; #endif namespace Detail { template std::string rangeToString(InputIterator first, InputIterator last) { ReusableStringStream rss; rss << "{ "; if (first != last) { rss << ::Catch::Detail::stringify(*first); for (++first; first != last; ++first) rss << ", " << ::Catch::Detail::stringify(*first); } rss << " }"; return rss.str(); } } #ifdef __OBJC__ template<> struct StringMaker { static std::string convert(NSString * nsstring) { if (!nsstring) return "nil"; return std::string("@") + [nsstring UTF8String]; } }; template<> struct StringMaker { static std::string convert(NSObject* nsObject) { return ::Catch::Detail::stringify([nsObject description]); } }; namespace Detail { inline std::string stringify( NSString* nsstring ) { return StringMaker::convert( nsstring ); } } // namespace Detail #endif // __OBJC__ } // namespace Catch ////////////////////////////////////////////////////// // Separate std-lib types stringification, so it can be selectively enabled // This means that we do not bring in #if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) # define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER # define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER #endif // Separate std::pair specialization #if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) #include namespace Catch { template struct StringMaker > { static std::string convert(const std::pair& pair) { ReusableStringStream rss; rss << "{ " << ::Catch::Detail::stringify(pair.first) << ", " << ::Catch::Detail::stringify(pair.second) << " }"; return rss.str(); } }; } #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER // Separate std::tuple specialization #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) #include namespace Catch { namespace Detail { template< typename Tuple, std::size_t N = 0, bool = (N < std::tuple_size::value) > struct TupleElementPrinter { static void print(const Tuple& tuple, std::ostream& os) { os << (N ? ", " : " ") << ::Catch::Detail::stringify(std::get(tuple)); TupleElementPrinter::print(tuple, os); } }; template< typename Tuple, std::size_t N > struct TupleElementPrinter { static void print(const Tuple&, std::ostream&) {} }; } template struct StringMaker> { static std::string convert(const std::tuple& tuple) { ReusableStringStream rss; rss << '{'; Detail::TupleElementPrinter>::print(tuple, rss.get()); rss << " }"; return rss.str(); } }; } #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER namespace Catch { struct not_this_one {}; // Tag type for detecting which begin/ end are being selected // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace using std::begin; using std::end; not_this_one begin( ... ); not_this_one end( ... ); template struct is_range { static const bool value = !std::is_same())), not_this_one>::value && !std::is_same())), not_this_one>::value; }; #if defined(_MANAGED) // Managed types are never ranges template struct is_range { static const bool value = false; }; #endif template std::string rangeToString( Range const& range ) { return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); } // Handle vector specially template std::string rangeToString( std::vector const& v ) { ReusableStringStream rss; rss << "{ "; bool first = true; for( bool b : v ) { if( first ) first = false; else rss << ", "; rss << ::Catch::Detail::stringify( b ); } rss << " }"; return rss.str(); } template struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>::type> { static std::string convert( R const& range ) { return rangeToString( range ); } }; template struct StringMaker { static std::string convert(T const(&arr)[SZ]) { return rangeToString(arr); } }; } // namespace Catch // Separate std::chrono::duration specialization #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) #include #include #include namespace Catch { template struct ratio_string { static std::string symbol(); }; template std::string ratio_string::symbol() { Catch::ReusableStringStream rss; rss << '[' << Ratio::num << '/' << Ratio::den << ']'; return rss.str(); } template <> struct ratio_string { static std::string symbol(); }; template <> struct ratio_string { static std::string symbol(); }; template <> struct ratio_string { static std::string symbol(); }; template <> struct ratio_string { static std::string symbol(); }; template <> struct ratio_string { static std::string symbol(); }; template <> struct ratio_string { static std::string symbol(); }; //////////// // std::chrono::duration specializations template struct StringMaker> { static std::string convert(std::chrono::duration const& duration) { ReusableStringStream rss; rss << duration.count() << ' ' << ratio_string::symbol() << 's'; return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { ReusableStringStream rss; rss << duration.count() << " s"; return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { ReusableStringStream rss; rss << duration.count() << " m"; return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { ReusableStringStream rss; rss << duration.count() << " h"; return rss.str(); } }; //////////// // std::chrono::time_point specialization // Generic time_point cannot be specialized, only std::chrono::time_point template struct StringMaker> { static std::string convert(std::chrono::time_point const& time_point) { return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; } }; // std::chrono::time_point specialization template struct StringMaker> { static std::string convert(std::chrono::time_point const& time_point) { auto converted = std::chrono::system_clock::to_time_t(time_point); #ifdef _MSC_VER std::tm timeInfo = {}; gmtime_s(&timeInfo, &converted); #else std::tm* timeInfo = std::gmtime(&converted); #endif auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); char timeStamp[timeStampSize]; const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; #ifdef _MSC_VER std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); #else std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif return std::string(timeStamp); } }; } #endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER #ifdef _MSC_VER #pragma warning(pop) #endif // end catch_tostring.h #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4389) // '==' : signed/unsigned mismatch #pragma warning(disable:4018) // more "signed/unsigned mismatch" #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) #pragma warning(disable:4180) // qualifier applied to function type has no meaning #endif namespace Catch { struct ITransientExpression { auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } auto getResult() const -> bool { return m_result; } virtual void streamReconstructedExpression( std::ostream &os ) const = 0; ITransientExpression( bool isBinaryExpression, bool result ) : m_isBinaryExpression( isBinaryExpression ), m_result( result ) {} // We don't actually need a virtual destructor, but many static analysers // complain if it's not here :-( virtual ~ITransientExpression(); bool m_isBinaryExpression; bool m_result; }; void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); template class BinaryExpr : public ITransientExpression { LhsT m_lhs; StringRef m_op; RhsT m_rhs; void streamReconstructedExpression( std::ostream &os ) const override { formatReconstructedExpression ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); } public: BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) : ITransientExpression{ true, comparisonResult }, m_lhs( lhs ), m_op( op ), m_rhs( rhs ) {} }; template class UnaryExpr : public ITransientExpression { LhsT m_lhs; void streamReconstructedExpression( std::ostream &os ) const override { os << Catch::Detail::stringify( m_lhs ); } public: explicit UnaryExpr( LhsT lhs ) : ITransientExpression{ false, lhs ? true : false }, m_lhs( lhs ) {} }; // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) template auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast(lhs == rhs); } template auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } template auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } template auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } template auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } template auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast(lhs != rhs); } template auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } template auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } template auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } template auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } template class ExprLhs { LhsT m_lhs; public: explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} template auto operator == ( RhsT const& rhs ) -> BinaryExpr const { return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; } auto operator == ( bool rhs ) -> BinaryExpr const { return { m_lhs == rhs, m_lhs, "==", rhs }; } template auto operator != ( RhsT const& rhs ) -> BinaryExpr const { return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; } auto operator != ( bool rhs ) -> BinaryExpr const { return { m_lhs != rhs, m_lhs, "!=", rhs }; } template auto operator > ( RhsT const& rhs ) -> BinaryExpr const { return { static_cast(m_lhs > rhs), m_lhs, ">", rhs }; } template auto operator < ( RhsT const& rhs ) -> BinaryExpr const { return { static_cast(m_lhs < rhs), m_lhs, "<", rhs }; } template auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { return { static_cast(m_lhs >= rhs), m_lhs, ">=", rhs }; } template auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; } auto makeUnaryExpr() const -> UnaryExpr { return UnaryExpr{ m_lhs }; } }; void handleExpression( ITransientExpression const& expr ); template void handleExpression( ExprLhs const& expr ) { handleExpression( expr.makeUnaryExpr() ); } struct Decomposer { template auto operator <= ( T const& lhs ) -> ExprLhs { return ExprLhs{ lhs }; } auto operator <=( bool value ) -> ExprLhs { return ExprLhs{ value }; } }; } // end namespace Catch #ifdef _MSC_VER #pragma warning(pop) #endif // end catch_decomposer.h // start catch_interfaces_capture.h #include namespace Catch { class AssertionResult; struct AssertionInfo; struct SectionInfo; struct SectionEndInfo; struct MessageInfo; struct Counts; struct BenchmarkInfo; struct BenchmarkStats; struct AssertionReaction; struct ITransientExpression; struct IResultCapture { virtual ~IResultCapture(); virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; virtual void handleFatalErrorCondition( StringRef message ) = 0; virtual void handleExpr ( AssertionInfo const& info, ITransientExpression const& expr, AssertionReaction& reaction ) = 0; virtual void handleMessage ( AssertionInfo const& info, ResultWas::OfType resultType, StringRef const& message, AssertionReaction& reaction ) = 0; virtual void handleUnexpectedExceptionNotThrown ( AssertionInfo const& info, AssertionReaction& reaction ) = 0; virtual void handleUnexpectedInflightException ( AssertionInfo const& info, std::string const& message, AssertionReaction& reaction ) = 0; virtual void handleIncomplete ( AssertionInfo const& info ) = 0; virtual void handleNonExpr ( AssertionInfo const &info, ResultWas::OfType resultType, AssertionReaction &reaction ) = 0; virtual bool lastAssertionPassed() = 0; virtual void assertionPassed() = 0; // Deprecated, do not use: virtual std::string getCurrentTestName() const = 0; virtual const AssertionResult* getLastResult() const = 0; virtual void exceptionEarlyReported() = 0; }; IResultCapture& getResultCapture(); } // end catch_interfaces_capture.h namespace Catch { struct TestFailureException{}; struct AssertionResultData; struct IResultCapture; class RunContext; class LazyExpression { friend class AssertionHandler; friend struct AssertionStats; friend class RunContext; ITransientExpression const* m_transientExpression = nullptr; bool m_isNegated; public: LazyExpression( bool isNegated ); LazyExpression( LazyExpression const& other ); LazyExpression& operator = ( LazyExpression const& ) = delete; explicit operator bool() const; friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; }; struct AssertionReaction { bool shouldDebugBreak = false; bool shouldThrow = false; }; class AssertionHandler { AssertionInfo m_assertionInfo; AssertionReaction m_reaction; bool m_completed = false; IResultCapture& m_resultCapture; public: AssertionHandler ( StringRef macroName, SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ); ~AssertionHandler() { if ( !m_completed ) { m_resultCapture.handleIncomplete( m_assertionInfo ); } } template void handleExpr( ExprLhs const& expr ) { handleExpr( expr.makeUnaryExpr() ); } void handleExpr( ITransientExpression const& expr ); void handleMessage(ResultWas::OfType resultType, StringRef const& message); void handleExceptionThrownAsExpected(); void handleUnexpectedExceptionNotThrown(); void handleExceptionNotThrownAsExpected(); void handleThrowingCallSkipped(); void handleUnexpectedInflightException(); void complete(); void setCompleted(); // query auto allowThrows() const -> bool; }; void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); } // namespace Catch // end catch_assertionhandler.h // start catch_message.h #include namespace Catch { struct MessageInfo { MessageInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ); std::string macroName; std::string message; SourceLineInfo lineInfo; ResultWas::OfType type; unsigned int sequence; bool operator == ( MessageInfo const& other ) const; bool operator < ( MessageInfo const& other ) const; private: static unsigned int globalCount; }; struct MessageStream { template MessageStream& operator << ( T const& value ) { m_stream << value; return *this; } ReusableStringStream m_stream; }; struct MessageBuilder : MessageStream { MessageBuilder( std::string const& macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ); template MessageBuilder& operator << ( T const& value ) { m_stream << value; return *this; } MessageInfo m_info; }; class ScopedMessage { public: explicit ScopedMessage( MessageBuilder const& builder ); ~ScopedMessage(); MessageInfo m_info; }; } // end namespace Catch // end catch_message.h #if !defined(CATCH_CONFIG_DISABLE) #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ #else #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" #endif #if defined(CATCH_CONFIG_FAST_COMPILE) /////////////////////////////////////////////////////////////////////////////// // Another way to speed-up compilation is to omit local try-catch for REQUIRE* // macros. #define INTERNAL_CATCH_TRY #define INTERNAL_CATCH_CATCH( capturer ) #else // CATCH_CONFIG_FAST_COMPILE #define INTERNAL_CATCH_TRY try #define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } #endif #define INTERNAL_CATCH_REACT( handler ) handler.complete(); /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ INTERNAL_CATCH_TRY { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( (void)0, false && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ if( Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ if( !Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ try { \ static_cast(__VA_ARGS__); \ catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ } \ catch( ... ) { \ catchAssertionHandler.handleUnexpectedInflightException(); \ } \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ else \ catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(expr); \ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ) { \ catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ catch( ... ) { \ catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( macroName, log ) \ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); /////////////////////////////////////////////////////////////////////////////// // Although this is matcher-based, it can be used with just a string #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ } \ else \ catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) #endif // CATCH_CONFIG_DISABLE // end catch_capture.hpp // start catch_section.h // start catch_section_info.h // start catch_totals.h #include namespace Catch { struct Counts { Counts operator - ( Counts const& other ) const; Counts& operator += ( Counts const& other ); std::size_t total() const; bool allPassed() const; bool allOk() const; std::size_t passed = 0; std::size_t failed = 0; std::size_t failedButOk = 0; }; struct Totals { Totals operator - ( Totals const& other ) const; Totals& operator += ( Totals const& other ); Totals delta( Totals const& prevTotals ) const; int error = 0; Counts assertions; Counts testCases; }; } // end catch_totals.h #include namespace Catch { struct SectionInfo { SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, std::string const& _description = std::string() ); std::string name; std::string description; SourceLineInfo lineInfo; }; struct SectionEndInfo { SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ); SectionInfo sectionInfo; Counts prevAssertions; double durationInSeconds; }; } // end namespace Catch // end catch_section_info.h // start catch_timer.h #include namespace Catch { auto getCurrentNanosecondsSinceEpoch() -> uint64_t; auto getEstimatedClockResolution() -> uint64_t; class Timer { uint64_t m_nanoseconds = 0; public: void start(); auto getElapsedNanoseconds() const -> uint64_t; auto getElapsedMicroseconds() const -> uint64_t; auto getElapsedMilliseconds() const -> unsigned int; auto getElapsedSeconds() const -> double; }; } // namespace Catch // end catch_timer.h #include namespace Catch { class Section : NonCopyable { public: Section( SectionInfo const& info ); ~Section(); // This indicates whether the section should be executed or not explicit operator bool() const; private: SectionInfo m_info; std::string m_name; Counts m_assertions; bool m_sectionIncluded; Timer m_timer; }; } // end namespace Catch #define INTERNAL_CATCH_SECTION( ... ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) // end catch_section.h // start catch_benchmark.h #include #include namespace Catch { class BenchmarkLooper { std::string m_name; std::size_t m_count = 0; std::size_t m_iterationsToRun = 1; uint64_t m_resolution; Timer m_timer; static auto getResolution() -> uint64_t; public: // Keep most of this inline as it's on the code path that is being timed BenchmarkLooper( StringRef name ) : m_name( name ), m_resolution( getResolution() ) { reportStart(); m_timer.start(); } explicit operator bool() { if( m_count < m_iterationsToRun ) return true; return needsMoreIterations(); } void increment() { ++m_count; } void reportStart(); auto needsMoreIterations() -> bool; }; } // end namespace Catch #define BENCHMARK( name ) \ for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) // end catch_benchmark.h // start catch_interfaces_exception.h // start catch_interfaces_registry_hub.h #include #include namespace Catch { class TestCase; struct ITestCaseRegistry; struct IExceptionTranslatorRegistry; struct IExceptionTranslator; struct IReporterRegistry; struct IReporterFactory; struct ITagAliasRegistry; class StartupExceptionRegistry; using IReporterFactoryPtr = std::shared_ptr; struct IRegistryHub { virtual ~IRegistryHub(); virtual IReporterRegistry const& getReporterRegistry() const = 0; virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; }; struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; virtual void registerStartupException() noexcept = 0; }; IRegistryHub& getRegistryHub(); IMutableRegistryHub& getMutableRegistryHub(); void cleanUp(); std::string translateActiveException(); } // end catch_interfaces_registry_hub.h #if defined(CATCH_CONFIG_DISABLE) #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ static std::string translatorName( signature ) #endif #include #include #include namespace Catch { using exceptionTranslateFunction = std::string(*)(); struct IExceptionTranslator; using ExceptionTranslators = std::vector>; struct IExceptionTranslator { virtual ~IExceptionTranslator(); virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; }; struct IExceptionTranslatorRegistry { virtual ~IExceptionTranslatorRegistry(); virtual std::string translateActiveException() const = 0; }; class ExceptionTranslatorRegistrar { template class ExceptionTranslator : public IExceptionTranslator { public: ExceptionTranslator( std::string(*translateFunction)( T& ) ) : m_translateFunction( translateFunction ) {} std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { try { if( it == itEnd ) std::rethrow_exception(std::current_exception()); else return (*it)->translate( it+1, itEnd ); } catch( T& ex ) { return m_translateFunction( ex ); } } protected: std::string(*m_translateFunction)( T& ); }; public: template ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { getMutableRegistryHub().registerTranslator ( new ExceptionTranslator( translateFunction ) ); } }; } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ static std::string translatorName( signature ); \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ static std::string translatorName( signature ) #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) // end catch_interfaces_exception.h // start catch_approx.h #include #include namespace Catch { namespace Detail { class Approx { private: bool equalityComparisonImpl(double other) const; public: explicit Approx ( double value ); static Approx custom(); template ::value>::type> Approx operator()( T const& value ) { Approx approx( static_cast(value) ); approx.epsilon( m_epsilon ); approx.margin( m_margin ); approx.scale( m_scale ); return approx; } template ::value>::type> explicit Approx( T const& value ): Approx(static_cast(value)) {} template ::value>::type> friend bool operator == ( const T& lhs, Approx const& rhs ) { auto lhs_v = static_cast(lhs); return rhs.equalityComparisonImpl(lhs_v); } template ::value>::type> friend bool operator == ( Approx const& lhs, const T& rhs ) { return operator==( rhs, lhs ); } template ::value>::type> friend bool operator != ( T const& lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } template ::value>::type> friend bool operator != ( Approx const& lhs, T const& rhs ) { return !operator==( rhs, lhs ); } template ::value>::type> friend bool operator <= ( T const& lhs, Approx const& rhs ) { return static_cast(lhs) < rhs.m_value || lhs == rhs; } template ::value>::type> friend bool operator <= ( Approx const& lhs, T const& rhs ) { return lhs.m_value < static_cast(rhs) || lhs == rhs; } template ::value>::type> friend bool operator >= ( T const& lhs, Approx const& rhs ) { return static_cast(lhs) > rhs.m_value || lhs == rhs; } template ::value>::type> friend bool operator >= ( Approx const& lhs, T const& rhs ) { return lhs.m_value > static_cast(rhs) || lhs == rhs; } template ::value>::type> Approx& epsilon( T const& newEpsilon ) { double epsilonAsDouble = static_cast(newEpsilon); if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) { throw std::domain_error ( "Invalid Approx::epsilon: " + Catch::Detail::stringify( epsilonAsDouble ) + ", Approx::epsilon has to be between 0 and 1" ); } m_epsilon = epsilonAsDouble; return *this; } template ::value>::type> Approx& margin( T const& newMargin ) { double marginAsDouble = static_cast(newMargin); if( marginAsDouble < 0 ) { throw std::domain_error ( "Invalid Approx::margin: " + Catch::Detail::stringify( marginAsDouble ) + ", Approx::Margin has to be non-negative." ); } m_margin = marginAsDouble; return *this; } template ::value>::type> Approx& scale( T const& newScale ) { m_scale = static_cast(newScale); return *this; } std::string toString() const; private: double m_epsilon; double m_margin; double m_scale; double m_value; }; } template<> struct StringMaker { static std::string convert(Catch::Detail::Approx const& value); }; } // end namespace Catch // end catch_approx.h // start catch_string_manip.h #include #include namespace Catch { bool startsWith( std::string const& s, std::string const& prefix ); bool startsWith( std::string const& s, char prefix ); bool endsWith( std::string const& s, std::string const& suffix ); bool endsWith( std::string const& s, char suffix ); bool contains( std::string const& s, std::string const& infix ); void toLowerInPlace( std::string& s ); std::string toLower( std::string const& s ); std::string trim( std::string const& str ); bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); struct pluralise { pluralise( std::size_t count, std::string const& label ); friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); std::size_t m_count; std::string m_label; }; } // end catch_string_manip.h #ifndef CATCH_CONFIG_DISABLE_MATCHERS // start catch_capture_matchers.h // start catch_matchers.h #include #include namespace Catch { namespace Matchers { namespace Impl { template struct MatchAllOf; template struct MatchAnyOf; template struct MatchNotOf; class MatcherUntypedBase { public: MatcherUntypedBase() = default; MatcherUntypedBase ( MatcherUntypedBase const& ) = default; MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; std::string toString() const; protected: virtual ~MatcherUntypedBase(); virtual std::string describe() const = 0; mutable std::string m_cachedToString; }; template struct MatcherMethod { virtual bool match( ObjectT const& arg ) const = 0; }; template struct MatcherMethod { virtual bool match( PtrT* arg ) const = 0; }; template struct MatcherBase : MatcherUntypedBase, MatcherMethod { MatchAllOf operator && ( MatcherBase const& other ) const; MatchAnyOf operator || ( MatcherBase const& other ) const; MatchNotOf operator ! () const; }; template struct MatchAllOf : MatcherBase { bool match( ArgT const& arg ) const override { for( auto matcher : m_matchers ) { if (!matcher->match(arg)) return false; } return true; } std::string describe() const override { std::string description; description.reserve( 4 + m_matchers.size()*32 ); description += "( "; bool first = true; for( auto matcher : m_matchers ) { if( first ) first = false; else description += " and "; description += matcher->toString(); } description += " )"; return description; } MatchAllOf& operator && ( MatcherBase const& other ) { m_matchers.push_back( &other ); return *this; } std::vector const*> m_matchers; }; template struct MatchAnyOf : MatcherBase { bool match( ArgT const& arg ) const override { for( auto matcher : m_matchers ) { if (matcher->match(arg)) return true; } return false; } std::string describe() const override { std::string description; description.reserve( 4 + m_matchers.size()*32 ); description += "( "; bool first = true; for( auto matcher : m_matchers ) { if( first ) first = false; else description += " or "; description += matcher->toString(); } description += " )"; return description; } MatchAnyOf& operator || ( MatcherBase const& other ) { m_matchers.push_back( &other ); return *this; } std::vector const*> m_matchers; }; template struct MatchNotOf : MatcherBase { MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} bool match( ArgT const& arg ) const override { return !m_underlyingMatcher.match( arg ); } std::string describe() const override { return "not " + m_underlyingMatcher.toString(); } MatcherBase const& m_underlyingMatcher; }; template MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { return MatchAllOf() && *this && other; } template MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { return MatchAnyOf() || *this || other; } template MatchNotOf MatcherBase::operator ! () const { return MatchNotOf( *this ); } } // namespace Impl } // namespace Matchers using namespace Matchers; using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.h // start catch_matchers_floating.h #include #include namespace Catch { namespace Matchers { namespace Floating { enum class FloatingPointKind : uint8_t; struct WithinAbsMatcher : MatcherBase { WithinAbsMatcher(double target, double margin); bool match(double const& matchee) const override; std::string describe() const override; private: double m_target; double m_margin; }; struct WithinUlpsMatcher : MatcherBase { WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); bool match(double const& matchee) const override; std::string describe() const override; private: double m_target; int m_ulps; FloatingPointKind m_type; }; } // namespace Floating // The following functions create the actual matcher objects. // This allows the types to be inferred Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); Floating::WithinAbsMatcher WithinAbs(double target, double margin); } // namespace Matchers } // namespace Catch // end catch_matchers_floating.h // start catch_matchers_generic.hpp #include #include namespace Catch { namespace Matchers { namespace Generic { namespace Detail { std::string finalizeDescription(const std::string& desc); } template class PredicateMatcher : public MatcherBase { std::function m_predicate; std::string m_description; public: PredicateMatcher(std::function const& elem, std::string const& descr) :m_predicate(std::move(elem)), m_description(Detail::finalizeDescription(descr)) {} bool match( T const& item ) const override { return m_predicate(item); } std::string describe() const override { return m_description; } }; } // namespace Generic // The following functions create the actual matcher objects. // The user has to explicitly specify type to the function, because // infering std::function is hard (but possible) and // requires a lot of TMP. template Generic::PredicateMatcher Predicate(std::function const& predicate, std::string const& description = "") { return Generic::PredicateMatcher(predicate, description); } } // namespace Matchers } // namespace Catch // end catch_matchers_generic.hpp // start catch_matchers_string.h #include namespace Catch { namespace Matchers { namespace StdString { struct CasedString { CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); std::string adjustString( std::string const& str ) const; std::string caseSensitivitySuffix() const; CaseSensitive::Choice m_caseSensitivity; std::string m_str; }; struct StringMatcherBase : MatcherBase { StringMatcherBase( std::string const& operation, CasedString const& comparator ); std::string describe() const override; CasedString m_comparator; std::string m_operation; }; struct EqualsMatcher : StringMatcherBase { EqualsMatcher( CasedString const& comparator ); bool match( std::string const& source ) const override; }; struct ContainsMatcher : StringMatcherBase { ContainsMatcher( CasedString const& comparator ); bool match( std::string const& source ) const override; }; struct StartsWithMatcher : StringMatcherBase { StartsWithMatcher( CasedString const& comparator ); bool match( std::string const& source ) const override; }; struct EndsWithMatcher : StringMatcherBase { EndsWithMatcher( CasedString const& comparator ); bool match( std::string const& source ) const override; }; struct RegexMatcher : MatcherBase { RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); bool match( std::string const& matchee ) const override; std::string describe() const override; private: std::string m_regex; CaseSensitive::Choice m_caseSensitivity; }; } // namespace StdString // The following functions create the actual matcher objects. // This allows the types to be inferred StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); } // namespace Matchers } // namespace Catch // end catch_matchers_string.h // start catch_matchers_vector.h #include namespace Catch { namespace Matchers { namespace Vector { namespace Detail { template size_t count(InputIterator first, InputIterator last, T const& item) { size_t cnt = 0; for (; first != last; ++first) { if (*first == item) { ++cnt; } } return cnt; } template bool contains(InputIterator first, InputIterator last, T const& item) { for (; first != last; ++first) { if (*first == item) { return true; } } return false; } } template struct ContainsElementMatcher : MatcherBase> { ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} bool match(std::vector const &v) const override { for (auto const& el : v) { if (el == m_comparator) { return true; } } return false; } std::string describe() const override { return "Contains: " + ::Catch::Detail::stringify( m_comparator ); } T const& m_comparator; }; template struct ContainsMatcher : MatcherBase> { ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} bool match(std::vector const &v) const override { // !TBD: see note in EqualsMatcher if (m_comparator.size() > v.size()) return false; for (auto const& comparator : m_comparator) { auto present = false; for (const auto& el : v) { if (el == comparator) { present = true; break; } } if (!present) { return false; } } return true; } std::string describe() const override { return "Contains: " + ::Catch::Detail::stringify( m_comparator ); } std::vector const& m_comparator; }; template struct EqualsMatcher : MatcherBase> { EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} bool match(std::vector const &v) const override { // !TBD: This currently works if all elements can be compared using != // - a more general approach would be via a compare template that defaults // to using !=. but could be specialised for, e.g. std::vector etc // - then just call that directly if (m_comparator.size() != v.size()) return false; for (std::size_t i = 0; i < v.size(); ++i) if (m_comparator[i] != v[i]) return false; return true; } std::string describe() const override { return "Equals: " + ::Catch::Detail::stringify( m_comparator ); } std::vector const& m_comparator; }; template struct UnorderedEqualsMatcher : MatcherBase> { UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} bool match(std::vector const& vec) const override { // Note: This is a reimplementation of std::is_permutation, // because I don't want to include inside the common path if (m_target.size() != vec.size()) { return false; } auto lfirst = m_target.begin(), llast = m_target.end(); auto rfirst = vec.begin(), rlast = vec.end(); // Cut common prefix to optimize checking of permuted parts while (lfirst != llast && *lfirst != *rfirst) { ++lfirst; ++rfirst; } if (lfirst == llast) { return true; } for (auto mid = lfirst; mid != llast; ++mid) { // Skip already counted items if (Detail::contains(lfirst, mid, *mid)) { continue; } size_t num_vec = Detail::count(rfirst, rlast, *mid); if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { return false; } } return true; } std::string describe() const override { return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); } private: std::vector const& m_target; }; } // namespace Vector // The following functions create the actual matcher objects. // This allows the types to be inferred template Vector::ContainsMatcher Contains( std::vector const& comparator ) { return Vector::ContainsMatcher( comparator ); } template Vector::ContainsElementMatcher VectorContains( T const& comparator ) { return Vector::ContainsElementMatcher( comparator ); } template Vector::EqualsMatcher Equals( std::vector const& comparator ) { return Vector::EqualsMatcher( comparator ); } template Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { return Vector::UnorderedEqualsMatcher(target); } } // namespace Matchers } // namespace Catch // end catch_matchers_vector.h namespace Catch { template class MatchExpr : public ITransientExpression { ArgT const& m_arg; MatcherT m_matcher; StringRef m_matcherString; public: MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) : ITransientExpression{ true, matcher.match( arg ) }, m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} void streamReconstructedExpression( std::ostream &os ) const override { auto matcherAsString = m_matcher.toString(); os << Catch::Detail::stringify( m_arg ) << ' '; if( matcherAsString == Detail::unprintableString ) os << m_matcherString; else os << matcherAsString; } }; using StringMatcher = Matchers::Impl::MatcherBase; void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); template auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { return MatchExpr( arg, matcher, matcherString ); } } // namespace Catch /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ INTERNAL_CATCH_TRY { \ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__ ); \ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ex ) { \ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ } \ catch( ... ) { \ catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) // end catch_capture_matchers.h #endif // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections // start catch_test_case_info.h #include #include #include #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { struct ITestInvoker; struct TestCaseInfo { enum SpecialProperties{ None = 0, IsHidden = 1 << 1, ShouldFail = 1 << 2, MayFail = 1 << 3, Throws = 1 << 4, NonPortable = 1 << 5, Benchmark = 1 << 6 }; TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, std::vector const& _tags, SourceLineInfo const& _lineInfo ); friend void setTags( TestCaseInfo& testCaseInfo, std::vector tags ); bool isHidden() const; bool throws() const; bool okToFail() const; bool expectedToFail() const; std::string tagsAsString() const; std::string name; std::string className; std::string description; std::vector tags; std::vector lcaseTags; SourceLineInfo lineInfo; SpecialProperties properties; }; class TestCase : public TestCaseInfo { public: TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); TestCase withName( std::string const& _newName ) const; void invoke() const; TestCaseInfo const& getTestCaseInfo() const; bool operator == ( TestCase const& other ) const; bool operator < ( TestCase const& other ) const; private: std::shared_ptr test; }; TestCase makeTestCase( ITestInvoker* testCase, std::string const& className, NameAndTags const& nameAndTags, SourceLineInfo const& lineInfo ); } #ifdef __clang__ #pragma clang diagnostic pop #endif // end catch_test_case_info.h // start catch_interfaces_runner.h namespace Catch { struct IRunner { virtual ~IRunner(); virtual bool aborting() const = 0; }; } // end catch_interfaces_runner.h #ifdef __OBJC__ // start catch_objc.hpp #import #include // NB. Any general catch headers included here must be included // in catch.hpp first to make sure they are included by the single // header for non obj-usage /////////////////////////////////////////////////////////////////////////////// // This protocol is really only here for (self) documenting purposes, since // all its methods are optional. @protocol OcFixture @optional -(void) setUp; -(void) tearDown; @end namespace Catch { class OcMethod : public ITestInvoker { public: OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} virtual void invoke() const { id obj = [[m_cls alloc] init]; performOptionalSelector( obj, @selector(setUp) ); performOptionalSelector( obj, m_sel ); performOptionalSelector( obj, @selector(tearDown) ); arcSafeRelease( obj ); } private: virtual ~OcMethod() {} Class m_cls; SEL m_sel; }; namespace Detail{ inline std::string getAnnotation( Class cls, std::string const& annotationName, std::string const& testCaseName ) { NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; SEL sel = NSSelectorFromString( selStr ); arcSafeRelease( selStr ); id value = performOptionalSelector( cls, sel ); if( value ) return [(NSString*)value UTF8String]; return ""; } } inline std::size_t registerTestMethods() { std::size_t noTestMethods = 0; int noClasses = objc_getClassList( nullptr, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); for( int c = 0; c < noClasses; c++ ) { Class cls = classes[c]; { u_int count; Method* methods = class_copyMethodList( cls, &count ); for( u_int m = 0; m < count ; m++ ) { SEL selector = method_getName(methods[m]); std::string methodName = sel_getName(selector); if( startsWith( methodName, "Catch_TestCase_" ) ) { std::string testCaseName = methodName.substr( 15 ); std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); const char* className = class_getName( cls ); getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) ); noTestMethods++; } } free(methods); } } return noTestMethods; } #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) namespace Matchers { namespace Impl { namespace NSStringMatchers { struct StringHolder : MatcherBase{ StringHolder( NSString* substr ) : m_substr( [substr copy] ){} StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} StringHolder() { arcSafeRelease( m_substr ); } bool match( NSString* arg ) const override { return false; } NSString* CATCH_ARC_STRONG m_substr; }; struct Equals : StringHolder { Equals( NSString* substr ) : StringHolder( substr ){} bool match( NSString* str ) const override { return (str != nil || m_substr == nil ) && [str isEqualToString:m_substr]; } std::string describe() const override { return "equals string: " + Catch::Detail::stringify( m_substr ); } }; struct Contains : StringHolder { Contains( NSString* substr ) : StringHolder( substr ){} bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location != NSNotFound; } std::string describe() const override { return "contains string: " + Catch::Detail::stringify( m_substr ); } }; struct StartsWith : StringHolder { StartsWith( NSString* substr ) : StringHolder( substr ){} bool match( NSString* str ) const override { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == 0; } std::string describe() const override { return "starts with: " + Catch::Detail::stringify( m_substr ); } }; struct EndsWith : StringHolder { EndsWith( NSString* substr ) : StringHolder( substr ){} bool match( NSString* str ) const override { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } std::string describe() const override { return "ends with: " + Catch::Detail::stringify( m_substr ); } }; } // namespace NSStringMatchers } // namespace Impl inline Impl::NSStringMatchers::Equals Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } inline Impl::NSStringMatchers::Contains Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } inline Impl::NSStringMatchers::StartsWith StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } inline Impl::NSStringMatchers::EndsWith EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } } // namespace Matchers using namespace Matchers; #endif // CATCH_CONFIG_DISABLE_MATCHERS } // namespace Catch /////////////////////////////////////////////////////////////////////////////// #define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix #define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ { \ return @ name; \ } \ +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ { \ return @ desc; \ } \ -(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) #define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) // end catch_objc.hpp #endif #ifdef CATCH_CONFIG_EXTERNAL_INTERFACES // start catch_external_interfaces.h // start catch_reporter_bases.hpp // start catch_interfaces_reporter.h // start catch_config.hpp // start catch_test_spec_parser.h #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif // start catch_test_spec.h #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif // start catch_wildcard_pattern.h namespace Catch { class WildcardPattern { enum WildcardPosition { NoWildcard = 0, WildcardAtStart = 1, WildcardAtEnd = 2, WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd }; public: WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); virtual ~WildcardPattern() = default; virtual bool matches( std::string const& str ) const; private: std::string adjustCase( std::string const& str ) const; CaseSensitive::Choice m_caseSensitivity; WildcardPosition m_wildcard = NoWildcard; std::string m_pattern; }; } // end catch_wildcard_pattern.h #include #include #include namespace Catch { class TestSpec { struct Pattern { virtual ~Pattern(); virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; using PatternPtr = std::shared_ptr; class NamePattern : public Pattern { public: NamePattern( std::string const& name ); virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const override; private: WildcardPattern m_wildcardPattern; }; class TagPattern : public Pattern { public: TagPattern( std::string const& tag ); virtual ~TagPattern(); virtual bool matches( TestCaseInfo const& testCase ) const override; private: std::string m_tag; }; class ExcludedPattern : public Pattern { public: ExcludedPattern( PatternPtr const& underlyingPattern ); virtual ~ExcludedPattern(); virtual bool matches( TestCaseInfo const& testCase ) const override; private: PatternPtr m_underlyingPattern; }; struct Filter { std::vector m_patterns; bool matches( TestCaseInfo const& testCase ) const; }; public: bool hasFilters() const; bool matches( TestCaseInfo const& testCase ) const; private: std::vector m_filters; friend class TestSpecParser; }; } #ifdef __clang__ #pragma clang diagnostic pop #endif // end catch_test_spec.h // start catch_interfaces_tag_alias_registry.h #include namespace Catch { struct TagAlias; struct ITagAliasRegistry { virtual ~ITagAliasRegistry(); // Nullptr if not present virtual TagAlias const* find( std::string const& alias ) const = 0; virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; static ITagAliasRegistry const& get(); }; } // end namespace Catch // end catch_interfaces_tag_alias_registry.h namespace Catch { class TestSpecParser { enum Mode{ None, Name, QuotedName, Tag, EscapedName }; Mode m_mode = None; bool m_exclusion = false; std::size_t m_start = std::string::npos, m_pos = 0; std::string m_arg; std::vector m_escapeChars; TestSpec::Filter m_currentFilter; TestSpec m_testSpec; ITagAliasRegistry const* m_tagAliases = nullptr; public: TestSpecParser( ITagAliasRegistry const& tagAliases ); TestSpecParser& parse( std::string const& arg ); TestSpec testSpec(); private: void visitChar( char c ); void startNewMode( Mode mode, std::size_t start ); void escape(); std::string subString() const; template void addPattern() { std::string token = subString(); for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); m_escapeChars.clear(); if( startsWith( token, "exclude:" ) ) { m_exclusion = true; token = token.substr( 8 ); } if( !token.empty() ) { TestSpec::PatternPtr pattern = std::make_shared( token ); if( m_exclusion ) pattern = std::make_shared( pattern ); m_currentFilter.m_patterns.push_back( pattern ); } m_exclusion = false; m_mode = None; } void addFilter(); }; TestSpec parseTestSpec( std::string const& arg ); } // namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif // end catch_test_spec_parser.h // start catch_interfaces_config.h #include #include #include #include namespace Catch { enum class Verbosity { Quiet = 0, Normal, High }; struct WarnAbout { enum What { Nothing = 0x00, NoAssertions = 0x01, NoTests = 0x02 }; }; struct ShowDurations { enum OrNot { DefaultForReporter, Always, Never }; }; struct RunTests { enum InWhatOrder { InDeclarationOrder, InLexicographicalOrder, InRandomOrder }; }; struct UseColour { enum YesOrNo { Auto, Yes, No }; }; struct WaitForKeypress { enum When { Never, BeforeStart = 1, BeforeExit = 2, BeforeStartAndExit = BeforeStart | BeforeExit }; }; class TestSpec; struct IConfig : NonCopyable { virtual ~IConfig(); virtual bool allowThrows() const = 0; virtual std::ostream& stream() const = 0; virtual std::string name() const = 0; virtual bool includeSuccessfulResults() const = 0; virtual bool shouldDebugBreak() const = 0; virtual bool warnAboutMissingAssertions() const = 0; virtual bool warnAboutNoTests() const = 0; virtual int abortAfter() const = 0; virtual bool showInvisibles() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; virtual TestSpec const& testSpec() const = 0; virtual bool hasTestFilters() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; virtual int benchmarkResolutionMultiple() const = 0; virtual UseColour::YesOrNo useColour() const = 0; virtual std::vector const& getSectionsToRun() const = 0; virtual Verbosity verbosity() const = 0; }; using IConfigPtr = std::shared_ptr; } // end catch_interfaces_config.h // Libstdc++ doesn't like incomplete classes for unique_ptr #include #include #include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 #endif namespace Catch { struct IStream; struct ConfigData { bool listTests = false; bool listTags = false; bool listReporters = false; bool listTestNamesOnly = false; bool showSuccessfulTests = false; bool shouldDebugBreak = false; bool noThrow = false; bool showHelp = false; bool showInvisibles = false; bool filenamesAsTags = false; bool libIdentify = false; int abortAfter = -1; unsigned int rngSeed = 0; int benchmarkResolutionMultiple = 100; Verbosity verbosity = Verbosity::Normal; WarnAbout::What warnings = WarnAbout::Nothing; ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; UseColour::YesOrNo useColour = UseColour::Auto; WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; std::string outputFilename; std::string name; std::string processName; #ifndef CATCH_CONFIG_DEFAULT_REPORTER #define CATCH_CONFIG_DEFAULT_REPORTER "console" #endif std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; #undef CATCH_CONFIG_DEFAULT_REPORTER std::vector testsOrTags; std::vector sectionsToRun; }; class Config : public IConfig { public: Config() = default; Config( ConfigData const& data ); virtual ~Config() = default; std::string const& getFilename() const; bool listTests() const; bool listTestNamesOnly() const; bool listTags() const; bool listReporters() const; std::string getProcessName() const; std::string const& getReporterName() const; std::vector const& getTestsOrTags() const; std::vector const& getSectionsToRun() const override; virtual TestSpec const& testSpec() const override; bool hasTestFilters() const override; bool showHelp() const; // IConfig interface bool allowThrows() const override; std::ostream& stream() const override; std::string name() const override; bool includeSuccessfulResults() const override; bool warnAboutMissingAssertions() const override; bool warnAboutNoTests() const override; ShowDurations::OrNot showDurations() const override; RunTests::InWhatOrder runOrder() const override; unsigned int rngSeed() const override; int benchmarkResolutionMultiple() const override; UseColour::YesOrNo useColour() const override; bool shouldDebugBreak() const override; int abortAfter() const override; bool showInvisibles() const override; Verbosity verbosity() const override; private: IStream const* openStream(); ConfigData m_data; std::unique_ptr m_stream; TestSpec m_testSpec; bool m_hasTestFilters = false; }; } // end namespace Catch // end catch_config.hpp // start catch_assertionresult.h #include namespace Catch { struct AssertionResultData { AssertionResultData() = delete; AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); std::string message; mutable std::string reconstructedExpression; LazyExpression lazyExpression; ResultWas::OfType resultType; std::string reconstructExpression() const; }; class AssertionResult { public: AssertionResult() = delete; AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); bool isOk() const; bool succeeded() const; ResultWas::OfType getResultType() const; bool hasExpression() const; bool hasMessage() const; std::string getExpression() const; std::string getExpressionInMacro() const; bool hasExpandedExpression() const; std::string getExpandedExpression() const; std::string getMessage() const; SourceLineInfo getSourceInfo() const; StringRef getTestMacroName() const; //protected: AssertionInfo m_info; AssertionResultData m_resultData; }; } // end namespace Catch // end catch_assertionresult.h // start catch_option.hpp namespace Catch { // An optional type template class Option { public: Option() : nullableValue( nullptr ) {} Option( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Option( Option const& _other ) : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) {} ~Option() { reset(); } Option& operator= ( Option const& _other ) { if( &_other != this ) { reset(); if( _other ) nullableValue = new( storage ) T( *_other ); } return *this; } Option& operator = ( T const& _value ) { reset(); nullableValue = new( storage ) T( _value ); return *this; } void reset() { if( nullableValue ) nullableValue->~T(); nullableValue = nullptr; } T& operator*() { return *nullableValue; } T const& operator*() const { return *nullableValue; } T* operator->() { return nullableValue; } const T* operator->() const { return nullableValue; } T valueOr( T const& defaultValue ) const { return nullableValue ? *nullableValue : defaultValue; } bool some() const { return nullableValue != nullptr; } bool none() const { return nullableValue == nullptr; } bool operator !() const { return nullableValue == nullptr; } explicit operator bool() const { return some(); } private: T *nullableValue; alignas(alignof(T)) char storage[sizeof(T)]; }; } // end namespace Catch // end catch_option.hpp #include #include #include #include #include namespace Catch { struct ReporterConfig { explicit ReporterConfig( IConfigPtr const& _fullConfig ); ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); std::ostream& stream() const; IConfigPtr fullConfig() const; private: std::ostream* m_stream; IConfigPtr m_fullConfig; }; struct ReporterPreferences { bool shouldRedirectStdOut = false; }; template struct LazyStat : Option { LazyStat& operator=( T const& _value ) { Option::operator=( _value ); used = false; return *this; } void reset() { Option::reset(); used = false; } bool used = false; }; struct TestRunInfo { TestRunInfo( std::string const& _name ); std::string name; }; struct GroupInfo { GroupInfo( std::string const& _name, std::size_t _groupIndex, std::size_t _groupsCount ); std::string name; std::size_t groupIndex; std::size_t groupsCounts; }; struct AssertionStats { AssertionStats( AssertionResult const& _assertionResult, std::vector const& _infoMessages, Totals const& _totals ); AssertionStats( AssertionStats const& ) = default; AssertionStats( AssertionStats && ) = default; AssertionStats& operator = ( AssertionStats const& ) = default; AssertionStats& operator = ( AssertionStats && ) = default; virtual ~AssertionStats(); AssertionResult assertionResult; std::vector infoMessages; Totals totals; }; struct SectionStats { SectionStats( SectionInfo const& _sectionInfo, Counts const& _assertions, double _durationInSeconds, bool _missingAssertions ); SectionStats( SectionStats const& ) = default; SectionStats( SectionStats && ) = default; SectionStats& operator = ( SectionStats const& ) = default; SectionStats& operator = ( SectionStats && ) = default; virtual ~SectionStats(); SectionInfo sectionInfo; Counts assertions; double durationInSeconds; bool missingAssertions; }; struct TestCaseStats { TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, std::string const& _stdOut, std::string const& _stdErr, bool _aborting ); TestCaseStats( TestCaseStats const& ) = default; TestCaseStats( TestCaseStats && ) = default; TestCaseStats& operator = ( TestCaseStats const& ) = default; TestCaseStats& operator = ( TestCaseStats && ) = default; virtual ~TestCaseStats(); TestCaseInfo testInfo; Totals totals; std::string stdOut; std::string stdErr; bool aborting; }; struct TestGroupStats { TestGroupStats( GroupInfo const& _groupInfo, Totals const& _totals, bool _aborting ); TestGroupStats( GroupInfo const& _groupInfo ); TestGroupStats( TestGroupStats const& ) = default; TestGroupStats( TestGroupStats && ) = default; TestGroupStats& operator = ( TestGroupStats const& ) = default; TestGroupStats& operator = ( TestGroupStats && ) = default; virtual ~TestGroupStats(); GroupInfo groupInfo; Totals totals; bool aborting; }; struct TestRunStats { TestRunStats( TestRunInfo const& _runInfo, Totals const& _totals, bool _aborting ); TestRunStats( TestRunStats const& ) = default; TestRunStats( TestRunStats && ) = default; TestRunStats& operator = ( TestRunStats const& ) = default; TestRunStats& operator = ( TestRunStats && ) = default; virtual ~TestRunStats(); TestRunInfo runInfo; Totals totals; bool aborting; }; struct BenchmarkInfo { std::string name; }; struct BenchmarkStats { BenchmarkInfo info; std::size_t iterations; uint64_t elapsedTimeInNanoseconds; }; struct IStreamingReporter { virtual ~IStreamingReporter() = default; // Implementing class must also provide the following static methods: // static std::string getDescription(); // static std::set getSupportedVerbosities() virtual ReporterPreferences getPreferences() const = 0; virtual void noMatchingTestCases( std::string const& spec ) = 0; virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; // *** experimental *** virtual void benchmarkStarting( BenchmarkInfo const& ) {} virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; // *** experimental *** virtual void benchmarkEnded( BenchmarkStats const& ) {} virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0; // Default empty implementation provided virtual void fatalErrorEncountered( StringRef name ); virtual bool isMulti() const; }; using IStreamingReporterPtr = std::unique_ptr; struct IReporterFactory { virtual ~IReporterFactory(); virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; using IReporterFactoryPtr = std::shared_ptr; struct IReporterRegistry { using FactoryMap = std::map; using Listeners = std::vector; virtual ~IReporterRegistry(); virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; virtual Listeners const& getListeners() const = 0; }; } // end namespace Catch // end catch_interfaces_reporter.h #include #include #include #include #include #include #include namespace Catch { void prepareExpandedExpression(AssertionResult& result); // Returns double formatted as %.3f (format expected on output) std::string getFormattedDuration( double duration ); template struct StreamingReporterBase : IStreamingReporter { StreamingReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) throw std::domain_error( "Verbosity level not supported by this reporter" ); } ReporterPreferences getPreferences() const override { return m_reporterPrefs; } static std::set getSupportedVerbosities() { return { Verbosity::Normal }; } ~StreamingReporterBase() override = default; void noMatchingTestCases(std::string const&) override {} void testRunStarting(TestRunInfo const& _testRunInfo) override { currentTestRunInfo = _testRunInfo; } void testGroupStarting(GroupInfo const& _groupInfo) override { currentGroupInfo = _groupInfo; } void testCaseStarting(TestCaseInfo const& _testInfo) override { currentTestCaseInfo = _testInfo; } void sectionStarting(SectionInfo const& _sectionInfo) override { m_sectionStack.push_back(_sectionInfo); } void sectionEnded(SectionStats const& /* _sectionStats */) override { m_sectionStack.pop_back(); } void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { currentTestCaseInfo.reset(); } void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { currentGroupInfo.reset(); } void testRunEnded(TestRunStats const& /* _testRunStats */) override { currentTestCaseInfo.reset(); currentGroupInfo.reset(); currentTestRunInfo.reset(); } void skipTest(TestCaseInfo const&) override { // Don't do anything with this by default. // It can optionally be overridden in the derived class. } IConfigPtr m_config; std::ostream& stream; LazyStat currentTestRunInfo; LazyStat currentGroupInfo; LazyStat currentTestCaseInfo; std::vector m_sectionStack; ReporterPreferences m_reporterPrefs; }; template struct CumulativeReporterBase : IStreamingReporter { template struct Node { explicit Node( T const& _value ) : value( _value ) {} virtual ~Node() {} using ChildNodes = std::vector>; T value; ChildNodes children; }; struct SectionNode { explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} virtual ~SectionNode() = default; bool operator == (SectionNode const& other) const { return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; } bool operator == (std::shared_ptr const& other) const { return operator==(*other); } SectionStats stats; using ChildSections = std::vector>; using Assertions = std::vector; ChildSections childSections; Assertions assertions; std::string stdOut; std::string stdErr; }; struct BySectionInfo { BySectionInfo( SectionInfo const& other ) : m_other( other ) {} BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} bool operator() (std::shared_ptr const& node) const { return ((node->stats.sectionInfo.name == m_other.name) && (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); } void operator=(BySectionInfo const&) = delete; private: SectionInfo const& m_other; }; using TestCaseNode = Node; using TestGroupNode = Node; using TestRunNode = Node; CumulativeReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) throw std::domain_error( "Verbosity level not supported by this reporter" ); } ~CumulativeReporterBase() override = default; ReporterPreferences getPreferences() const override { return m_reporterPrefs; } static std::set getSupportedVerbosities() { return { Verbosity::Normal }; } void testRunStarting( TestRunInfo const& ) override {} void testGroupStarting( GroupInfo const& ) override {} void testCaseStarting( TestCaseInfo const& ) override {} void sectionStarting( SectionInfo const& sectionInfo ) override { SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); std::shared_ptr node; if( m_sectionStack.empty() ) { if( !m_rootSection ) m_rootSection = std::make_shared( incompleteStats ); node = m_rootSection; } else { SectionNode& parentNode = *m_sectionStack.back(); auto it = std::find_if( parentNode.childSections.begin(), parentNode.childSections.end(), BySectionInfo( sectionInfo ) ); if( it == parentNode.childSections.end() ) { node = std::make_shared( incompleteStats ); parentNode.childSections.push_back( node ); } else node = *it; } m_sectionStack.push_back( node ); m_deepestSection = std::move(node); } void assertionStarting(AssertionInfo const&) override {} bool assertionEnded(AssertionStats const& assertionStats) override { assert(!m_sectionStack.empty()); // AssertionResult holds a pointer to a temporary DecomposedExpression, // which getExpandedExpression() calls to build the expression string. // Our section stack copy of the assertionResult will likely outlive the // temporary, so it must be expanded or discarded now to avoid calling // a destroyed object later. prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); SectionNode& sectionNode = *m_sectionStack.back(); sectionNode.assertions.push_back(assertionStats); return true; } void sectionEnded(SectionStats const& sectionStats) override { assert(!m_sectionStack.empty()); SectionNode& node = *m_sectionStack.back(); node.stats = sectionStats; m_sectionStack.pop_back(); } void testCaseEnded(TestCaseStats const& testCaseStats) override { auto node = std::make_shared(testCaseStats); assert(m_sectionStack.size() == 0); node->children.push_back(m_rootSection); m_testCases.push_back(node); m_rootSection.reset(); assert(m_deepestSection); m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdErr = testCaseStats.stdErr; } void testGroupEnded(TestGroupStats const& testGroupStats) override { auto node = std::make_shared(testGroupStats); node->children.swap(m_testCases); m_testGroups.push_back(node); } void testRunEnded(TestRunStats const& testRunStats) override { auto node = std::make_shared(testRunStats); node->children.swap(m_testGroups); m_testRuns.push_back(node); testRunEndedCumulative(); } virtual void testRunEndedCumulative() = 0; void skipTest(TestCaseInfo const&) override {} IConfigPtr m_config; std::ostream& stream; std::vector m_assertions; std::vector>> m_sections; std::vector> m_testCases; std::vector> m_testGroups; std::vector> m_testRuns; std::shared_ptr m_rootSection; std::shared_ptr m_deepestSection; std::vector> m_sectionStack; ReporterPreferences m_reporterPrefs; }; template char const* getLineOfChars() { static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; if( !*line ) { std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; } return line; } struct TestEventListenerBase : StreamingReporterBase { TestEventListenerBase( ReporterConfig const& _config ); void assertionStarting(AssertionInfo const&) override; bool assertionEnded(AssertionStats const&) override; }; } // end namespace Catch // end catch_reporter_bases.hpp // start catch_console_colour.h namespace Catch { struct Colour { enum Code { None = 0, White, Red, Green, Blue, Cyan, Yellow, Grey, Bright = 0x10, BrightRed = Bright | Red, BrightGreen = Bright | Green, LightGrey = Bright | Grey, BrightWhite = Bright | White, BrightYellow = Bright | Yellow, // By intention FileName = LightGrey, Warning = BrightYellow, ResultError = BrightRed, ResultSuccess = BrightGreen, ResultExpectedFailure = Warning, Error = BrightRed, Success = Green, OriginalExpression = Cyan, ReconstructedExpression = BrightYellow, SecondaryText = LightGrey, Headers = White }; // Use constructed object for RAII guard Colour( Code _colourCode ); Colour( Colour&& other ) noexcept; Colour& operator=( Colour&& other ) noexcept; ~Colour(); // Use static method for one-shot changes static void use( Code _colourCode ); private: bool m_moved = false; }; std::ostream& operator << ( std::ostream& os, Colour const& ); } // end namespace Catch // end catch_console_colour.h // start catch_reporter_registrars.hpp namespace Catch { template class ReporterRegistrar { class ReporterFactory : public IReporterFactory { virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { return std::unique_ptr( new T( config ) ); } virtual std::string getDescription() const override { return T::getDescription(); } }; public: explicit ReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, std::make_shared() ); } }; template class ListenerRegistrar { class ListenerFactory : public IReporterFactory { virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { return std::unique_ptr( new T( config ) ); } virtual std::string getDescription() const override { return std::string(); } }; public: ListenerRegistrar() { getMutableRegistryHub().registerListener( std::make_shared() ); } }; } #if !defined(CATCH_CONFIG_DISABLE) #define CATCH_REGISTER_REPORTER( name, reporterType ) \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #define CATCH_REGISTER_LISTENER( listenerType ) \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS #else // CATCH_CONFIG_DISABLE #define CATCH_REGISTER_REPORTER(name, reporterType) #define CATCH_REGISTER_LISTENER(listenerType) #endif // CATCH_CONFIG_DISABLE // end catch_reporter_registrars.hpp // Allow users to base their work off existing reporters // start catch_reporter_compact.h namespace Catch { struct CompactReporter : StreamingReporterBase { using StreamingReporterBase::StreamingReporterBase; ~CompactReporter() override; static std::string getDescription(); ReporterPreferences getPreferences() const override; void noMatchingTestCases(std::string const& spec) override; void assertionStarting(AssertionInfo const&) override; bool assertionEnded(AssertionStats const& _assertionStats) override; void sectionEnded(SectionStats const& _sectionStats) override; void testRunEnded(TestRunStats const& _testRunStats) override; }; } // end namespace Catch // end catch_reporter_compact.h // start catch_reporter_console.h #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch // Note that 4062 (not all labels are handled // and default is missing) is enabled #endif namespace Catch { // Fwd decls struct SummaryColumn; class TablePrinter; struct ConsoleReporter : StreamingReporterBase { std::unique_ptr m_tablePrinter; ConsoleReporter(ReporterConfig const& config); ~ConsoleReporter() override; static std::string getDescription(); void noMatchingTestCases(std::string const& spec) override; void assertionStarting(AssertionInfo const&) override; bool assertionEnded(AssertionStats const& _assertionStats) override; void sectionStarting(SectionInfo const& _sectionInfo) override; void sectionEnded(SectionStats const& _sectionStats) override; void benchmarkStarting(BenchmarkInfo const& info) override; void benchmarkEnded(BenchmarkStats const& stats) override; void testCaseEnded(TestCaseStats const& _testCaseStats) override; void testGroupEnded(TestGroupStats const& _testGroupStats) override; void testRunEnded(TestRunStats const& _testRunStats) override; private: void lazyPrint(); void lazyPrintWithoutClosingBenchmarkTable(); void lazyPrintRunInfo(); void lazyPrintGroupInfo(); void printTestCaseAndSectionHeader(); void printClosedHeader(std::string const& _name); void printOpenHeader(std::string const& _name); // if string has a : in first line will set indent to follow it on // subsequent lines void printHeaderString(std::string const& _string, std::size_t indent = 0); void printTotals(Totals const& totals); void printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row); void printTotalsDivider(Totals const& totals); void printSummaryDivider(); private: bool m_headerPrinted = false; }; } // end namespace Catch #if defined(_MSC_VER) #pragma warning(pop) #endif // end catch_reporter_console.h // start catch_reporter_junit.h // start catch_xmlwriter.h #include namespace Catch { class XmlEncode { public: enum ForWhat { ForTextNodes, ForAttributes }; XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); void encodeTo( std::ostream& os ) const; friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); private: std::string m_str; ForWhat m_forWhat; }; class XmlWriter { public: class ScopedElement { public: ScopedElement( XmlWriter* writer ); ScopedElement( ScopedElement&& other ) noexcept; ScopedElement& operator=( ScopedElement&& other ) noexcept; ~ScopedElement(); ScopedElement& writeText( std::string const& text, bool indent = true ); template ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { m_writer->writeAttribute( name, attribute ); return *this; } private: mutable XmlWriter* m_writer = nullptr; }; XmlWriter( std::ostream& os = Catch::cout() ); ~XmlWriter(); XmlWriter( XmlWriter const& ) = delete; XmlWriter& operator=( XmlWriter const& ) = delete; XmlWriter& startElement( std::string const& name ); ScopedElement scopedElement( std::string const& name ); XmlWriter& endElement(); XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); XmlWriter& writeAttribute( std::string const& name, bool attribute ); template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { ReusableStringStream rss; rss << attribute; return writeAttribute( name, rss.str() ); } XmlWriter& writeText( std::string const& text, bool indent = true ); XmlWriter& writeComment( std::string const& text ); void writeStylesheetRef( std::string const& url ); XmlWriter& writeBlankLine(); void ensureTagClosed(); private: void writeDeclaration(); void newlineIfNecessary(); bool m_tagIsOpen = false; bool m_needsNewline = false; std::vector m_tags; std::string m_indent; std::ostream& m_os; }; } // end catch_xmlwriter.h namespace Catch { class JunitReporter : public CumulativeReporterBase { public: JunitReporter(ReporterConfig const& _config); ~JunitReporter() override; static std::string getDescription(); void noMatchingTestCases(std::string const& /*spec*/) override; void testRunStarting(TestRunInfo const& runInfo) override; void testGroupStarting(GroupInfo const& groupInfo) override; void testCaseStarting(TestCaseInfo const& testCaseInfo) override; bool assertionEnded(AssertionStats const& assertionStats) override; void testCaseEnded(TestCaseStats const& testCaseStats) override; void testGroupEnded(TestGroupStats const& testGroupStats) override; void testRunEndedCumulative() override; void writeGroup(TestGroupNode const& groupNode, double suiteTime); void writeTestCase(TestCaseNode const& testCaseNode); void writeSection(std::string const& className, std::string const& rootName, SectionNode const& sectionNode); void writeAssertions(SectionNode const& sectionNode); void writeAssertion(AssertionStats const& stats); XmlWriter xml; Timer suiteTimer; std::string stdOutForSuite; std::string stdErrForSuite; unsigned int unexpectedExceptions = 0; bool m_okToFail = false; }; } // end namespace Catch // end catch_reporter_junit.h // start catch_reporter_xml.h namespace Catch { class XmlReporter : public StreamingReporterBase { public: XmlReporter(ReporterConfig const& _config); ~XmlReporter() override; static std::string getDescription(); virtual std::string getStylesheetRef() const; void writeSourceInfo(SourceLineInfo const& sourceInfo); public: // StreamingReporterBase void noMatchingTestCases(std::string const& s) override; void testRunStarting(TestRunInfo const& testInfo) override; void testGroupStarting(GroupInfo const& groupInfo) override; void testCaseStarting(TestCaseInfo const& testInfo) override; void sectionStarting(SectionInfo const& sectionInfo) override; void assertionStarting(AssertionInfo const&) override; bool assertionEnded(AssertionStats const& assertionStats) override; void sectionEnded(SectionStats const& sectionStats) override; void testCaseEnded(TestCaseStats const& testCaseStats) override; void testGroupEnded(TestGroupStats const& testGroupStats) override; void testRunEnded(TestRunStats const& testRunStats) override; private: Timer m_testCaseTimer; XmlWriter m_xml; int m_sectionDepth = 0; }; } // end namespace Catch // end catch_reporter_xml.h // end catch_external_interfaces.h #endif #endif // ! CATCH_CONFIG_IMPL_ONLY #ifdef CATCH_IMPL // start catch_impl.hpp #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wweak-vtables" #endif // Keep these here for external reporters // start catch_test_case_tracker.h #include #include #include namespace Catch { namespace TestCaseTracking { struct NameAndLocation { std::string name; SourceLineInfo location; NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); }; struct ITracker; using ITrackerPtr = std::shared_ptr; struct ITracker { virtual ~ITracker(); // static queries virtual NameAndLocation const& nameAndLocation() const = 0; // dynamic queries virtual bool isComplete() const = 0; // Successfully completed or failed virtual bool isSuccessfullyCompleted() const = 0; virtual bool isOpen() const = 0; // Started but not complete virtual bool hasChildren() const = 0; virtual ITracker& parent() = 0; // actions virtual void close() = 0; // Successfully complete virtual void fail() = 0; virtual void markAsNeedingAnotherRun() = 0; virtual void addChild( ITrackerPtr const& child ) = 0; virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; virtual void openChild() = 0; // Debug/ checking virtual bool isSectionTracker() const = 0; virtual bool isIndexTracker() const = 0; }; class TrackerContext { enum RunState { NotStarted, Executing, CompletedCycle }; ITrackerPtr m_rootTracker; ITracker* m_currentTracker = nullptr; RunState m_runState = NotStarted; public: static TrackerContext& instance(); ITracker& startRun(); void endRun(); void startCycle(); void completeCycle(); bool completedCycle() const; ITracker& currentTracker(); void setCurrentTracker( ITracker* tracker ); }; class TrackerBase : public ITracker { protected: enum CycleState { NotStarted, Executing, ExecutingChildren, NeedsAnotherRun, CompletedSuccessfully, Failed }; class TrackerHasName { NameAndLocation m_nameAndLocation; public: TrackerHasName( NameAndLocation const& nameAndLocation ); bool operator ()( ITrackerPtr const& tracker ) const; }; using Children = std::vector; NameAndLocation m_nameAndLocation; TrackerContext& m_ctx; ITracker* m_parent; Children m_children; CycleState m_runState = NotStarted; public: TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); NameAndLocation const& nameAndLocation() const override; bool isComplete() const override; bool isSuccessfullyCompleted() const override; bool isOpen() const override; bool hasChildren() const override; void addChild( ITrackerPtr const& child ) override; ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; ITracker& parent() override; void openChild() override; bool isSectionTracker() const override; bool isIndexTracker() const override; void open(); void close() override; void fail() override; void markAsNeedingAnotherRun() override; private: void moveToParent(); void moveToThis(); }; class SectionTracker : public TrackerBase { std::vector m_filters; public: SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); bool isSectionTracker() const override; static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); void tryOpen(); void addInitialFilters( std::vector const& filters ); void addNextFilters( std::vector const& filters ); }; class IndexTracker : public TrackerBase { int m_size; int m_index = -1; public: IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); bool isIndexTracker() const override; void close() override; static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); int index() const; void moveNext(); }; } // namespace TestCaseTracking using TestCaseTracking::ITracker; using TestCaseTracking::TrackerContext; using TestCaseTracking::SectionTracker; using TestCaseTracking::IndexTracker; } // namespace Catch // end catch_test_case_tracker.h // start catch_leak_detector.h namespace Catch { struct LeakDetector { LeakDetector(); }; } // end catch_leak_detector.h // Cpp files will be included in the single-header file here // start catch_approx.cpp #include #include namespace { // Performs equivalent check of std::fabs(lhs - rhs) <= margin // But without the subtraction to allow for INFINITY in comparison bool marginComparison(double lhs, double rhs, double margin) { return (lhs + margin >= rhs) && (rhs + margin >= lhs); } } namespace Catch { namespace Detail { Approx::Approx ( double value ) : m_epsilon( std::numeric_limits::epsilon()*100 ), m_margin( 0.0 ), m_scale( 0.0 ), m_value( value ) {} Approx Approx::custom() { return Approx( 0 ); } std::string Approx::toString() const { ReusableStringStream rss; rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; return rss.str(); } bool Approx::equalityComparisonImpl(const double other) const { // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value // Thanks to Richard Harris for his help refining the scaled margin value return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); } } // end namespace Detail std::string StringMaker::convert(Catch::Detail::Approx const& value) { return value.toString(); } } // end namespace Catch // end catch_approx.cpp // start catch_assertionhandler.cpp // start catch_context.h #include namespace Catch { struct IResultCapture; struct IRunner; struct IConfig; struct IMutableContext; using IConfigPtr = std::shared_ptr; struct IContext { virtual ~IContext(); virtual IResultCapture* getResultCapture() = 0; virtual IRunner* getRunner() = 0; virtual IConfigPtr const& getConfig() const = 0; }; struct IMutableContext : IContext { virtual ~IMutableContext(); virtual void setResultCapture( IResultCapture* resultCapture ) = 0; virtual void setRunner( IRunner* runner ) = 0; virtual void setConfig( IConfigPtr const& config ) = 0; private: static IMutableContext *currentContext; friend IMutableContext& getCurrentMutableContext(); friend void cleanUpContext(); static void createContext(); }; inline IMutableContext& getCurrentMutableContext() { /* * False positive reported here: * https://github.com/catchorg/Catch2/issues/1230 * * and upstream: https://bugs.llvm.org/show_bug.cgi?id=39201 */ #ifndef __clang_analyzer__ if( !IMutableContext::currentContext ) IMutableContext::createContext(); #endif return *IMutableContext::currentContext; } inline IContext& getCurrentContext() { return getCurrentMutableContext(); } void cleanUpContext(); } // end catch_context.h // start catch_debugger.h namespace Catch { bool isDebuggerActive(); } #ifdef CATCH_PLATFORM_MAC #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ #elif defined(CATCH_PLATFORM_LINUX) // If we can use inline assembler, do it because this allows us to break // directly at the location of the failing check instead of breaking inside // raise() called from it, i.e. one stack frame below. #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ #else // Fall back to the generic way. #include #define CATCH_TRAP() raise(SIGTRAP) #endif #elif defined(_MSC_VER) #define CATCH_TRAP() __debugbreak() #elif defined(__MINGW32__) extern "C" __declspec(dllimport) void __stdcall DebugBreak(); #define CATCH_TRAP() DebugBreak() #endif #ifdef CATCH_TRAP #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } #else namespace Catch { inline void doNothing() {} } #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() #endif // end catch_debugger.h // start catch_run_context.h // start catch_fatal_condition.h // start catch_windows_h_proxy.h #if defined(CATCH_PLATFORM_WINDOWS) #if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) # define CATCH_DEFINED_NOMINMAX # define NOMINMAX #endif #if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) # define CATCH_DEFINED_WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif #ifdef __AFXDLL #include #else #include #endif #ifdef CATCH_DEFINED_NOMINMAX # undef NOMINMAX #endif #ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN # undef WIN32_LEAN_AND_MEAN #endif #endif // defined(CATCH_PLATFORM_WINDOWS) // end catch_windows_h_proxy.h #if defined( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { struct FatalConditionHandler { static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); FatalConditionHandler(); static void reset(); ~FatalConditionHandler(); private: static bool isSet; static ULONG guaranteeSize; static PVOID exceptionHandlerHandle; }; } // namespace Catch #elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) #include namespace Catch { struct FatalConditionHandler { static bool isSet; static struct sigaction oldSigActions[]; static stack_t oldSigStack; static char altStackMem[]; static void handleSignal( int sig ); FatalConditionHandler(); ~FatalConditionHandler(); static void reset(); }; } // namespace Catch #else namespace Catch { struct FatalConditionHandler { void reset(); }; } #endif // end catch_fatal_condition.h #include namespace Catch { struct IMutableContext; /////////////////////////////////////////////////////////////////////////// class RunContext : public IResultCapture, public IRunner { public: RunContext( RunContext const& ) = delete; RunContext& operator =( RunContext const& ) = delete; explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); ~RunContext() override; void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); Totals runTest(TestCase const& testCase); IConfigPtr config() const; IStreamingReporter& reporter() const; public: // IResultCapture // Assertion handlers void handleExpr ( AssertionInfo const& info, ITransientExpression const& expr, AssertionReaction& reaction ) override; void handleMessage ( AssertionInfo const& info, ResultWas::OfType resultType, StringRef const& message, AssertionReaction& reaction ) override; void handleUnexpectedExceptionNotThrown ( AssertionInfo const& info, AssertionReaction& reaction ) override; void handleUnexpectedInflightException ( AssertionInfo const& info, std::string const& message, AssertionReaction& reaction ) override; void handleIncomplete ( AssertionInfo const& info ) override; void handleNonExpr ( AssertionInfo const &info, ResultWas::OfType resultType, AssertionReaction &reaction ) override; bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; void sectionEnded( SectionEndInfo const& endInfo ) override; void sectionEndedEarly( SectionEndInfo const& endInfo ) override; void benchmarkStarting( BenchmarkInfo const& info ) override; void benchmarkEnded( BenchmarkStats const& stats ) override; void pushScopedMessage( MessageInfo const& message ) override; void popScopedMessage( MessageInfo const& message ) override; std::string getCurrentTestName() const override; const AssertionResult* getLastResult() const override; void exceptionEarlyReported() override; void handleFatalErrorCondition( StringRef message ) override; bool lastAssertionPassed() override; void assertionPassed() override; public: // !TBD We need to do this another way! bool aborting() const final; private: void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); void invokeActiveTestCase(); void resetAssertionInfo(); bool testForMissingAssertions( Counts& assertions ); void assertionEnded( AssertionResult const& result ); void reportExpr ( AssertionInfo const &info, ResultWas::OfType resultType, ITransientExpression const *expr, bool negated ); void populateReaction( AssertionReaction& reaction ); private: void handleUnfinishedSections(); TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase = nullptr; ITracker* m_testCaseTracker; Option m_lastResult; IConfigPtr m_config; Totals m_totals; IStreamingReporterPtr m_reporter; std::vector m_messages; AssertionInfo m_lastAssertionInfo; std::vector m_unfinishedSections; std::vector m_activeSections; TrackerContext m_trackerContext; bool m_lastAssertionPassed = false; bool m_shouldReportUnexpected = true; bool m_includeSuccessfulResults; }; } // end namespace Catch // end catch_run_context.h namespace Catch { auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { expr.streamReconstructedExpression( os ); return os; } LazyExpression::LazyExpression( bool isNegated ) : m_isNegated( isNegated ) {} LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} LazyExpression::operator bool() const { return m_transientExpression != nullptr; } auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { if( lazyExpr.m_isNegated ) os << "!"; if( lazyExpr ) { if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) os << "(" << *lazyExpr.m_transientExpression << ")"; else os << *lazyExpr.m_transientExpression; } else { os << "{** error - unchecked empty expression requested **}"; } return os; } AssertionHandler::AssertionHandler ( StringRef macroName, SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ) : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, m_resultCapture( getResultCapture() ) {} void AssertionHandler::handleExpr( ITransientExpression const& expr ) { m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); } void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); } auto AssertionHandler::allowThrows() const -> bool { return getCurrentContext().getConfig()->allowThrows(); } void AssertionHandler::complete() { setCompleted(); if( m_reaction.shouldDebugBreak ) { // If you find your debugger stopping you here then go one level up on the // call-stack for the code that caused it (typically a failed assertion) // (To go back to the test and change execution, jump over the throw, next) CATCH_BREAK_INTO_DEBUGGER(); } if( m_reaction.shouldThrow ) throw Catch::TestFailureException(); } void AssertionHandler::setCompleted() { m_completed = true; } void AssertionHandler::handleUnexpectedInflightException() { m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); } void AssertionHandler::handleExceptionThrownAsExpected() { m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); } void AssertionHandler::handleExceptionNotThrownAsExpected() { m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); } void AssertionHandler::handleUnexpectedExceptionNotThrown() { m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); } void AssertionHandler::handleThrowingCallSkipped() { m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); } // This is the overload that takes a string and infers the Equals matcher from it // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); } } // namespace Catch // end catch_assertionhandler.cpp // start catch_assertionresult.cpp namespace Catch { AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): lazyExpression(_lazyExpression), resultType(_resultType) {} std::string AssertionResultData::reconstructExpression() const { if( reconstructedExpression.empty() ) { if( lazyExpression ) { ReusableStringStream rss; rss << lazyExpression; reconstructedExpression = rss.str(); } } return reconstructedExpression; } AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) : m_info( info ), m_resultData( data ) {} // Result was a success bool AssertionResult::succeeded() const { return Catch::isOk( m_resultData.resultType ); } // Result was a success, or failure is suppressed bool AssertionResult::isOk() const { return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); } ResultWas::OfType AssertionResult::getResultType() const { return m_resultData.resultType; } bool AssertionResult::hasExpression() const { return m_info.capturedExpression[0] != 0; } bool AssertionResult::hasMessage() const { return !m_resultData.message.empty(); } std::string AssertionResult::getExpression() const { if( isFalseTest( m_info.resultDisposition ) ) return "!(" + m_info.capturedExpression + ")"; else return m_info.capturedExpression; } std::string AssertionResult::getExpressionInMacro() const { std::string expr; if( m_info.macroName[0] == 0 ) expr = m_info.capturedExpression; else { expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); expr += m_info.macroName; expr += "( "; expr += m_info.capturedExpression; expr += " )"; } return expr; } bool AssertionResult::hasExpandedExpression() const { return hasExpression() && getExpandedExpression() != getExpression(); } std::string AssertionResult::getExpandedExpression() const { std::string expr = m_resultData.reconstructExpression(); return expr.empty() ? getExpression() : expr; } std::string AssertionResult::getMessage() const { return m_resultData.message; } SourceLineInfo AssertionResult::getSourceInfo() const { return m_info.lineInfo; } StringRef AssertionResult::getTestMacroName() const { return m_info.macroName; } } // end namespace Catch // end catch_assertionresult.cpp // start catch_benchmark.cpp namespace Catch { auto BenchmarkLooper::getResolution() -> uint64_t { return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); } void BenchmarkLooper::reportStart() { getResultCapture().benchmarkStarting( { m_name } ); } auto BenchmarkLooper::needsMoreIterations() -> bool { auto elapsed = m_timer.getElapsedNanoseconds(); // Exponentially increasing iterations until we're confident in our timer resolution if( elapsed < m_resolution ) { m_iterationsToRun *= 10; return true; } getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); return false; } } // end namespace Catch // end catch_benchmark.cpp // start catch_capture_matchers.cpp namespace Catch { using StringMatcher = Matchers::Impl::MatcherBase; // This is the general overload that takes a any string matcher // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers // the Equals matcher (so the header does not mention matchers) void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { std::string exceptionMessage = Catch::translateActiveException(); MatchExpr expr( exceptionMessage, matcher, matcherString ); handler.handleExpr( expr ); } } // namespace Catch // end catch_capture_matchers.cpp // start catch_commandline.cpp // start catch_commandline.h // start catch_clara.h // Use Catch's value for console width (store Clara's off to the side, if present) #ifdef CLARA_CONFIG_CONSOLE_WIDTH #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH #undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH #endif #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wweak-vtables" #pragma clang diagnostic ignored "-Wexit-time-destructors" #pragma clang diagnostic ignored "-Wshadow" #endif // start clara.hpp // Copyright 2017 Two Blue Cubes Ltd. All rights reserved. // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See https://github.com/philsquared/Clara for more details // Clara v1.1.4 #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH #define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 #endif #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH #endif #ifndef CLARA_CONFIG_OPTIONAL_TYPE #ifdef __has_include #if __has_include() && __cplusplus >= 201703L #include #define CLARA_CONFIG_OPTIONAL_TYPE std::optional #endif #endif #endif // ----------- #included from clara_textflow.hpp ----------- // TextFlowCpp // // A single-header library for wrapping and laying out basic text, by Phil Nash // // This work is licensed under the BSD 2-Clause license. // See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause // // This project is hosted at https://github.com/philsquared/textflowcpp #include #include #include #include #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 #endif namespace Catch { namespace clara { namespace TextFlow { inline auto isWhitespace( char c ) -> bool { static std::string chars = " \t\n\r"; return chars.find( c ) != std::string::npos; } inline auto isBreakableBefore( char c ) -> bool { static std::string chars = "[({<|"; return chars.find( c ) != std::string::npos; } inline auto isBreakableAfter( char c ) -> bool { static std::string chars = "])}>.,:;*+-=&/\\"; return chars.find( c ) != std::string::npos; } class Columns; class Column { std::vector m_strings; size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; size_t m_indent = 0; size_t m_initialIndent = std::string::npos; public: class iterator { friend Column; Column const& m_column; size_t m_stringIndex = 0; size_t m_pos = 0; size_t m_len = 0; size_t m_end = 0; bool m_suffix = false; iterator( Column const& column, size_t stringIndex ) : m_column( column ), m_stringIndex( stringIndex ) {} auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } auto isBoundary( size_t at ) const -> bool { assert( at > 0 ); assert( at <= line().size() ); return at == line().size() || ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || isBreakableBefore( line()[at] ) || isBreakableAfter( line()[at-1] ); } void calcLength() { assert( m_stringIndex < m_column.m_strings.size() ); m_suffix = false; auto width = m_column.m_width-indent(); m_end = m_pos; while( m_end < line().size() && line()[m_end] != '\n' ) ++m_end; if( m_end < m_pos + width ) { m_len = m_end - m_pos; } else { size_t len = width; while (len > 0 && !isBoundary(m_pos + len)) --len; while (len > 0 && isWhitespace( line()[m_pos + len - 1] )) --len; if (len > 0) { m_len = len; } else { m_suffix = true; m_len = width - 1; } } } auto indent() const -> size_t { auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; return initial == std::string::npos ? m_column.m_indent : initial; } auto addIndentAndSuffix(std::string const &plain) const -> std::string { return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain); } public: explicit iterator( Column const& column ) : m_column( column ) { assert( m_column.m_width > m_column.m_indent ); assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); calcLength(); if( m_len == 0 ) m_stringIndex++; // Empty string } auto operator *() const -> std::string { assert( m_stringIndex < m_column.m_strings.size() ); assert( m_pos <= m_end ); if( m_pos + m_column.m_width < m_end ) return addIndentAndSuffix(line().substr(m_pos, m_len)); else return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); } auto operator ++() -> iterator& { m_pos += m_len; if( m_pos < line().size() && line()[m_pos] == '\n' ) m_pos += 1; else while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) ++m_pos; if( m_pos == line().size() ) { m_pos = 0; ++m_stringIndex; } if( m_stringIndex < m_column.m_strings.size() ) calcLength(); return *this; } auto operator ++(int) -> iterator { iterator prev( *this ); operator++(); return prev; } auto operator ==( iterator const& other ) const -> bool { return m_pos == other.m_pos && m_stringIndex == other.m_stringIndex && &m_column == &other.m_column; } auto operator !=( iterator const& other ) const -> bool { return !operator==( other ); } }; using const_iterator = iterator; explicit Column( std::string const& text ) { m_strings.push_back( text ); } auto width( size_t newWidth ) -> Column& { assert( newWidth > 0 ); m_width = newWidth; return *this; } auto indent( size_t newIndent ) -> Column& { m_indent = newIndent; return *this; } auto initialIndent( size_t newIndent ) -> Column& { m_initialIndent = newIndent; return *this; } auto width() const -> size_t { return m_width; } auto begin() const -> iterator { return iterator( *this ); } auto end() const -> iterator { return { *this, m_strings.size() }; } inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { bool first = true; for( auto line : col ) { if( first ) first = false; else os << "\n"; os << line; } return os; } auto operator + ( Column const& other ) -> Columns; auto toString() const -> std::string { std::ostringstream oss; oss << *this; return oss.str(); } }; class Spacer : public Column { public: explicit Spacer( size_t spaceWidth ) : Column( "" ) { width( spaceWidth ); } }; class Columns { std::vector m_columns; public: class iterator { friend Columns; struct EndTag {}; std::vector const& m_columns; std::vector m_iterators; size_t m_activeIterators; iterator( Columns const& columns, EndTag ) : m_columns( columns.m_columns ), m_activeIterators( 0 ) { m_iterators.reserve( m_columns.size() ); for( auto const& col : m_columns ) m_iterators.push_back( col.end() ); } public: explicit iterator( Columns const& columns ) : m_columns( columns.m_columns ), m_activeIterators( m_columns.size() ) { m_iterators.reserve( m_columns.size() ); for( auto const& col : m_columns ) m_iterators.push_back( col.begin() ); } auto operator ==( iterator const& other ) const -> bool { return m_iterators == other.m_iterators; } auto operator !=( iterator const& other ) const -> bool { return m_iterators != other.m_iterators; } auto operator *() const -> std::string { std::string row, padding; for( size_t i = 0; i < m_columns.size(); ++i ) { auto width = m_columns[i].width(); if( m_iterators[i] != m_columns[i].end() ) { std::string col = *m_iterators[i]; row += padding + col; if( col.size() < width ) padding = std::string( width - col.size(), ' ' ); else padding = ""; } else { padding += std::string( width, ' ' ); } } return row; } auto operator ++() -> iterator& { for( size_t i = 0; i < m_columns.size(); ++i ) { if (m_iterators[i] != m_columns[i].end()) ++m_iterators[i]; } return *this; } auto operator ++(int) -> iterator { iterator prev( *this ); operator++(); return prev; } }; using const_iterator = iterator; auto begin() const -> iterator { return iterator( *this ); } auto end() const -> iterator { return { *this, iterator::EndTag() }; } auto operator += ( Column const& col ) -> Columns& { m_columns.push_back( col ); return *this; } auto operator + ( Column const& col ) -> Columns { Columns combined = *this; combined += col; return combined; } inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) { bool first = true; for( auto line : cols ) { if( first ) first = false; else os << "\n"; os << line; } return os; } auto toString() const -> std::string { std::ostringstream oss; oss << *this; return oss.str(); } }; inline auto Column::operator + ( Column const& other ) -> Columns { Columns cols; cols += *this; cols += other; return cols; } }}} // namespace Catch::clara::TextFlow // ----------- end of #include from clara_textflow.hpp ----------- // ........... back in clara.hpp #include #include #include #if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) #define CATCH_PLATFORM_WINDOWS #endif namespace Catch { namespace clara { namespace detail { // Traits for extracting arg and return type of lambdas (for single argument lambdas) template struct UnaryLambdaTraits : UnaryLambdaTraits {}; template struct UnaryLambdaTraits { static const bool isValid = false; }; template struct UnaryLambdaTraits { static const bool isValid = true; using ArgType = typename std::remove_const::type>::type; using ReturnType = ReturnT; }; class TokenStream; // Transport for raw args (copied from main args, or supplied via init list for testing) class Args { friend TokenStream; std::string m_exeName; std::vector m_args; public: Args( int argc, char const* const* argv ) : m_exeName(argv[0]), m_args(argv + 1, argv + argc) {} Args( std::initializer_list args ) : m_exeName( *args.begin() ), m_args( args.begin()+1, args.end() ) {} auto exeName() const -> std::string { return m_exeName; } }; // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string // may encode an option + its argument if the : or = form is used enum class TokenType { Option, Argument }; struct Token { TokenType type; std::string token; }; inline auto isOptPrefix( char c ) -> bool { return c == '-' #ifdef CATCH_PLATFORM_WINDOWS || c == '/' #endif ; } // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled class TokenStream { using Iterator = std::vector::const_iterator; Iterator it; Iterator itEnd; std::vector m_tokenBuffer; void loadBuffer() { m_tokenBuffer.resize( 0 ); // Skip any empty strings while( it != itEnd && it->empty() ) ++it; if( it != itEnd ) { auto const &next = *it; if( isOptPrefix( next[0] ) ) { auto delimiterPos = next.find_first_of( " :=" ); if( delimiterPos != std::string::npos ) { m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); } else { if( next[1] != '-' && next.size() > 2 ) { std::string opt = "- "; for( size_t i = 1; i < next.size(); ++i ) { opt[1] = next[i]; m_tokenBuffer.push_back( { TokenType::Option, opt } ); } } else { m_tokenBuffer.push_back( { TokenType::Option, next } ); } } } else { m_tokenBuffer.push_back( { TokenType::Argument, next } ); } } } public: explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { loadBuffer(); } explicit operator bool() const { return !m_tokenBuffer.empty() || it != itEnd; } auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } auto operator*() const -> Token { assert( !m_tokenBuffer.empty() ); return m_tokenBuffer.front(); } auto operator->() const -> Token const * { assert( !m_tokenBuffer.empty() ); return &m_tokenBuffer.front(); } auto operator++() -> TokenStream & { if( m_tokenBuffer.size() >= 2 ) { m_tokenBuffer.erase( m_tokenBuffer.begin() ); } else { if( it != itEnd ) ++it; loadBuffer(); } return *this; } }; class ResultBase { public: enum Type { Ok, LogicError, RuntimeError }; protected: ResultBase( Type type ) : m_type( type ) {} virtual ~ResultBase() = default; virtual void enforceOk() const = 0; Type m_type; }; template class ResultValueBase : public ResultBase { public: auto value() const -> T const & { enforceOk(); return m_value; } protected: ResultValueBase( Type type ) : ResultBase( type ) {} ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { if( m_type == ResultBase::Ok ) new( &m_value ) T( other.m_value ); } ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { new( &m_value ) T( value ); } auto operator=( ResultValueBase const &other ) -> ResultValueBase & { if( m_type == ResultBase::Ok ) m_value.~T(); ResultBase::operator=(other); if( m_type == ResultBase::Ok ) new( &m_value ) T( other.m_value ); return *this; } ~ResultValueBase() override { if( m_type == Ok ) m_value.~T(); } union { T m_value; }; }; template<> class ResultValueBase : public ResultBase { protected: using ResultBase::ResultBase; }; template class BasicResult : public ResultValueBase { public: template explicit BasicResult( BasicResult const &other ) : ResultValueBase( other.type() ), m_errorMessage( other.errorMessage() ) { assert( type() != ResultBase::Ok ); } template static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } static auto ok() -> BasicResult { return { ResultBase::Ok }; } static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } explicit operator bool() const { return m_type == ResultBase::Ok; } auto type() const -> ResultBase::Type { return m_type; } auto errorMessage() const -> std::string { return m_errorMessage; } protected: void enforceOk() const override { // Errors shouldn't reach this point, but if they do // the actual error message will be in m_errorMessage assert( m_type != ResultBase::LogicError ); assert( m_type != ResultBase::RuntimeError ); if( m_type != ResultBase::Ok ) std::abort(); } std::string m_errorMessage; // Only populated if resultType is an error BasicResult( ResultBase::Type type, std::string const &message ) : ResultValueBase(type), m_errorMessage(message) { assert( m_type != ResultBase::Ok ); } using ResultValueBase::ResultValueBase; using ResultBase::m_type; }; enum class ParseResultType { Matched, NoMatch, ShortCircuitAll, ShortCircuitSame }; class ParseState { public: ParseState( ParseResultType type, TokenStream const &remainingTokens ) : m_type(type), m_remainingTokens( remainingTokens ) {} auto type() const -> ParseResultType { return m_type; } auto remainingTokens() const -> TokenStream { return m_remainingTokens; } private: ParseResultType m_type; TokenStream m_remainingTokens; }; using Result = BasicResult; using ParserResult = BasicResult; using InternalParseResult = BasicResult; struct HelpColumns { std::string left; std::string right; }; template inline auto convertInto( std::string const &source, T& target ) -> ParserResult { std::stringstream ss; ss << source; ss >> target; if( ss.fail() ) return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); else return ParserResult::ok( ParseResultType::Matched ); } inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { target = source; return ParserResult::ok( ParseResultType::Matched ); } inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { std::string srcLC = source; std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( ::tolower(c) ); } ); if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") target = true; else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") target = false; else return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); return ParserResult::ok( ParseResultType::Matched ); } #ifdef CLARA_CONFIG_OPTIONAL_TYPE template inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { T temp; auto result = convertInto( source, temp ); if( result ) target = std::move(temp); return result; } #endif // CLARA_CONFIG_OPTIONAL_TYPE struct NonCopyable { NonCopyable() = default; NonCopyable( NonCopyable const & ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable &operator=( NonCopyable const & ) = delete; NonCopyable &operator=( NonCopyable && ) = delete; }; struct BoundRef : NonCopyable { virtual ~BoundRef() = default; virtual auto isContainer() const -> bool { return false; } virtual auto isFlag() const -> bool { return false; } }; struct BoundValueRefBase : BoundRef { virtual auto setValue( std::string const &arg ) -> ParserResult = 0; }; struct BoundFlagRefBase : BoundRef { virtual auto setFlag( bool flag ) -> ParserResult = 0; virtual auto isFlag() const -> bool { return true; } }; template struct BoundValueRef : BoundValueRefBase { T &m_ref; explicit BoundValueRef( T &ref ) : m_ref( ref ) {} auto setValue( std::string const &arg ) -> ParserResult override { return convertInto( arg, m_ref ); } }; template struct BoundValueRef> : BoundValueRefBase { std::vector &m_ref; explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} auto isContainer() const -> bool override { return true; } auto setValue( std::string const &arg ) -> ParserResult override { T temp; auto result = convertInto( arg, temp ); if( result ) m_ref.push_back( temp ); return result; } }; struct BoundFlagRef : BoundFlagRefBase { bool &m_ref; explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} auto setFlag( bool flag ) -> ParserResult override { m_ref = flag; return ParserResult::ok( ParseResultType::Matched ); } }; template struct LambdaInvoker { static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); template static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { return lambda( arg ); } }; template<> struct LambdaInvoker { template static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { lambda( arg ); return ParserResult::ok( ParseResultType::Matched ); } }; template inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { ArgType temp{}; auto result = convertInto( arg, temp ); return !result ? result : LambdaInvoker::ReturnType>::invoke( lambda, temp ); } template struct BoundLambda : BoundValueRefBase { L m_lambda; static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} auto setValue( std::string const &arg ) -> ParserResult override { return invokeLambda::ArgType>( m_lambda, arg ); } }; template struct BoundFlagLambda : BoundFlagRefBase { L m_lambda; static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} auto setFlag( bool flag ) -> ParserResult override { return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); } }; enum class Optionality { Optional, Required }; struct Parser; class ParserBase { public: virtual ~ParserBase() = default; virtual auto validate() const -> Result { return Result::ok(); } virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; virtual auto cardinality() const -> size_t { return 1; } auto parse( Args const &args ) const -> InternalParseResult { return parse( args.exeName(), TokenStream( args ) ); } }; template class ComposableParserImpl : public ParserBase { public: template auto operator|( T const &other ) const -> Parser; template auto operator+( T const &other ) const -> Parser; }; // Common code and state for Args and Opts template class ParserRefImpl : public ComposableParserImpl { protected: Optionality m_optionality = Optionality::Optional; std::shared_ptr m_ref; std::string m_hint; std::string m_description; explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} public: template ParserRefImpl( T &ref, std::string const &hint ) : m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} template ParserRefImpl( LambdaT const &ref, std::string const &hint ) : m_ref( std::make_shared>( ref ) ), m_hint(hint) {} auto operator()( std::string const &description ) -> DerivedT & { m_description = description; return static_cast( *this ); } auto optional() -> DerivedT & { m_optionality = Optionality::Optional; return static_cast( *this ); }; auto required() -> DerivedT & { m_optionality = Optionality::Required; return static_cast( *this ); }; auto isOptional() const -> bool { return m_optionality == Optionality::Optional; } auto cardinality() const -> size_t override { if( m_ref->isContainer() ) return 0; else return 1; } auto hint() const -> std::string { return m_hint; } }; class ExeName : public ComposableParserImpl { std::shared_ptr m_name; std::shared_ptr m_ref; template static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { return std::make_shared>( lambda) ; } public: ExeName() : m_name( std::make_shared( "" ) ) {} explicit ExeName( std::string &ref ) : ExeName() { m_ref = std::make_shared>( ref ); } template explicit ExeName( LambdaT const& lambda ) : ExeName() { m_ref = std::make_shared>( lambda ); } // The exe name is not parsed out of the normal tokens, but is handled specially auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); } auto name() const -> std::string { return *m_name; } auto set( std::string const& newName ) -> ParserResult { auto lastSlash = newName.find_last_of( "\\/" ); auto filename = ( lastSlash == std::string::npos ) ? newName : newName.substr( lastSlash+1 ); *m_name = filename; if( m_ref ) return m_ref->setValue( filename ); else return ParserResult::ok( ParseResultType::Matched ); } }; class Arg : public ParserRefImpl { public: using ParserRefImpl::ParserRefImpl; auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { auto validationResult = validate(); if( !validationResult ) return InternalParseResult( validationResult ); auto remainingTokens = tokens; auto const &token = *remainingTokens; if( token.type != TokenType::Argument ) return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); assert( !m_ref->isFlag() ); auto valueRef = static_cast( m_ref.get() ); auto result = valueRef->setValue( remainingTokens->token ); if( !result ) return InternalParseResult( result ); else return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); } }; inline auto normaliseOpt( std::string const &optName ) -> std::string { #ifdef CATCH_PLATFORM_WINDOWS if( optName[0] == '/' ) return "-" + optName.substr( 1 ); else #endif return optName; } class Opt : public ParserRefImpl { protected: std::vector m_optNames; public: template explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared>( ref ) ) {} explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared( ref ) ) {} template Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} template Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} auto operator[]( std::string const &optName ) -> Opt & { m_optNames.push_back( optName ); return *this; } auto getHelpColumns() const -> std::vector { std::ostringstream oss; bool first = true; for( auto const &opt : m_optNames ) { if (first) first = false; else oss << ", "; oss << opt; } if( !m_hint.empty() ) oss << " <" << m_hint << ">"; return { { oss.str(), m_description } }; } auto isMatch( std::string const &optToken ) const -> bool { auto normalisedToken = normaliseOpt( optToken ); for( auto const &name : m_optNames ) { if( normaliseOpt( name ) == normalisedToken ) return true; } return false; } using ParserBase::parse; auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { auto validationResult = validate(); if( !validationResult ) return InternalParseResult( validationResult ); auto remainingTokens = tokens; if( remainingTokens && remainingTokens->type == TokenType::Option ) { auto const &token = *remainingTokens; if( isMatch(token.token ) ) { if( m_ref->isFlag() ) { auto flagRef = static_cast( m_ref.get() ); auto result = flagRef->setFlag( true ); if( !result ) return InternalParseResult( result ); if( result.value() == ParseResultType::ShortCircuitAll ) return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); } else { auto valueRef = static_cast( m_ref.get() ); ++remainingTokens; if( !remainingTokens ) return InternalParseResult::runtimeError( "Expected argument following " + token.token ); auto const &argToken = *remainingTokens; if( argToken.type != TokenType::Argument ) return InternalParseResult::runtimeError( "Expected argument following " + token.token ); auto result = valueRef->setValue( argToken.token ); if( !result ) return InternalParseResult( result ); if( result.value() == ParseResultType::ShortCircuitAll ) return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); } return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); } } return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); } auto validate() const -> Result override { if( m_optNames.empty() ) return Result::logicError( "No options supplied to Opt" ); for( auto const &name : m_optNames ) { if( name.empty() ) return Result::logicError( "Option name cannot be empty" ); #ifdef CATCH_PLATFORM_WINDOWS if( name[0] != '-' && name[0] != '/' ) return Result::logicError( "Option name must begin with '-' or '/'" ); #else if( name[0] != '-' ) return Result::logicError( "Option name must begin with '-'" ); #endif } return ParserRefImpl::validate(); } }; struct Help : Opt { Help( bool &showHelpFlag ) : Opt([&]( bool flag ) { showHelpFlag = flag; return ParserResult::ok( ParseResultType::ShortCircuitAll ); }) { static_cast( *this ) ("display usage information") ["-?"]["-h"]["--help"] .optional(); } }; struct Parser : ParserBase { mutable ExeName m_exeName; std::vector m_options; std::vector m_args; auto operator|=( ExeName const &exeName ) -> Parser & { m_exeName = exeName; return *this; } auto operator|=( Arg const &arg ) -> Parser & { m_args.push_back(arg); return *this; } auto operator|=( Opt const &opt ) -> Parser & { m_options.push_back(opt); return *this; } auto operator|=( Parser const &other ) -> Parser & { m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); return *this; } template auto operator|( T const &other ) const -> Parser { return Parser( *this ) |= other; } // Forward deprecated interface with '+' instead of '|' template auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } template auto operator+( T const &other ) const -> Parser { return operator|( other ); } auto getHelpColumns() const -> std::vector { std::vector cols; for (auto const &o : m_options) { auto childCols = o.getHelpColumns(); cols.insert( cols.end(), childCols.begin(), childCols.end() ); } return cols; } void writeToStream( std::ostream &os ) const { if (!m_exeName.name().empty()) { os << "usage:\n" << " " << m_exeName.name() << " "; bool required = true, first = true; for( auto const &arg : m_args ) { if (first) first = false; else os << " "; if( arg.isOptional() && required ) { os << "["; required = false; } os << "<" << arg.hint() << ">"; if( arg.cardinality() == 0 ) os << " ... "; } if( !required ) os << "]"; if( !m_options.empty() ) os << " options"; os << "\n\nwhere options are:" << std::endl; } auto rows = getHelpColumns(); size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; size_t optWidth = 0; for( auto const &cols : rows ) optWidth = (std::max)(optWidth, cols.left.size() + 2); optWidth = (std::min)(optWidth, consoleWidth/2); for( auto const &cols : rows ) { auto row = TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + TextFlow::Spacer(4) + TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); os << row << std::endl; } } friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { parser.writeToStream( os ); return os; } auto validate() const -> Result override { for( auto const &opt : m_options ) { auto result = opt.validate(); if( !result ) return result; } for( auto const &arg : m_args ) { auto result = arg.validate(); if( !result ) return result; } return Result::ok(); } using ParserBase::parse; auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { struct ParserInfo { ParserBase const* parser = nullptr; size_t count = 0; }; const size_t totalParsers = m_options.size() + m_args.size(); assert( totalParsers < 512 ); // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do ParserInfo parseInfos[512]; { size_t i = 0; for (auto const &opt : m_options) parseInfos[i++].parser = &opt; for (auto const &arg : m_args) parseInfos[i++].parser = &arg; } m_exeName.set( exeName ); auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); while( result.value().remainingTokens() ) { bool tokenParsed = false; for( size_t i = 0; i < totalParsers; ++i ) { auto& parseInfo = parseInfos[i]; if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); if (!result) return result; if (result.value().type() != ParseResultType::NoMatch) { tokenParsed = true; ++parseInfo.count; break; } } } if( result.value().type() == ParseResultType::ShortCircuitAll ) return result; if( !tokenParsed ) return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); } // !TBD Check missing required options return result; } }; template template auto ComposableParserImpl::operator|( T const &other ) const -> Parser { return Parser() | static_cast( *this ) | other; } } // namespace detail // A Combined parser using detail::Parser; // A parser for options using detail::Opt; // A parser for arguments using detail::Arg; // Wrapper for argc, argv from main() using detail::Args; // Specifies the name of the executable using detail::ExeName; // Convenience wrapper for option parser that specifies the help option using detail::Help; // enum of result types from a parse using detail::ParseResultType; // Result type for parser operation using detail::ParserResult; }} // namespace Catch::clara // end clara.hpp #ifdef __clang__ #pragma clang diagnostic pop #endif // Restore Clara's value for console width, if present #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #endif // end catch_clara.h namespace Catch { clara::Parser makeCommandLineParser( ConfigData& config ); } // end namespace Catch // end catch_commandline.h #include #include namespace Catch { clara::Parser makeCommandLineParser( ConfigData& config ) { using namespace clara; auto const setWarning = [&]( std::string const& warning ) { auto warningSet = [&]() { if( warning == "NoAssertions" ) return WarnAbout::NoAssertions; if ( warning == "NoTests" ) return WarnAbout::NoTests; return WarnAbout::Nothing; }(); if (warningSet == WarnAbout::Nothing) return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); config.warnings = static_cast( config.warnings | warningSet ); return ParserResult::ok( ParseResultType::Matched ); }; auto const loadTestNamesFromFile = [&]( std::string const& filename ) { std::ifstream f( filename.c_str() ); if( !f.is_open() ) return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); std::string line; while( std::getline( f, line ) ) { line = trim(line); if( !line.empty() && !startsWith( line, '#' ) ) { if( !startsWith( line, '"' ) ) line = '"' + line + '"'; config.testsOrTags.push_back( line + ',' ); } } return ParserResult::ok( ParseResultType::Matched ); }; auto const setTestOrder = [&]( std::string const& order ) { if( startsWith( "declared", order ) ) config.runOrder = RunTests::InDeclarationOrder; else if( startsWith( "lexical", order ) ) config.runOrder = RunTests::InLexicographicalOrder; else if( startsWith( "random", order ) ) config.runOrder = RunTests::InRandomOrder; else return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); return ParserResult::ok( ParseResultType::Matched ); }; auto const setRngSeed = [&]( std::string const& seed ) { if( seed != "time" ) return clara::detail::convertInto( seed, config.rngSeed ); config.rngSeed = static_cast( std::time(nullptr) ); return ParserResult::ok( ParseResultType::Matched ); }; auto const setColourUsage = [&]( std::string const& useColour ) { auto mode = toLower( useColour ); if( mode == "yes" ) config.useColour = UseColour::Yes; else if( mode == "no" ) config.useColour = UseColour::No; else if( mode == "auto" ) config.useColour = UseColour::Auto; else return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); return ParserResult::ok( ParseResultType::Matched ); }; auto const setWaitForKeypress = [&]( std::string const& keypress ) { auto keypressLc = toLower( keypress ); if( keypressLc == "start" ) config.waitForKeypress = WaitForKeypress::BeforeStart; else if( keypressLc == "exit" ) config.waitForKeypress = WaitForKeypress::BeforeExit; else if( keypressLc == "both" ) config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; else return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); return ParserResult::ok( ParseResultType::Matched ); }; auto const setVerbosity = [&]( std::string const& verbosity ) { auto lcVerbosity = toLower( verbosity ); if( lcVerbosity == "quiet" ) config.verbosity = Verbosity::Quiet; else if( lcVerbosity == "normal" ) config.verbosity = Verbosity::Normal; else if( lcVerbosity == "high" ) config.verbosity = Verbosity::High; else return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); return ParserResult::ok( ParseResultType::Matched ); }; auto cli = ExeName( config.processName ) | Help( config.showHelp ) | Opt( config.listTests ) ["-l"]["--list-tests"] ( "list all/matching test cases" ) | Opt( config.listTags ) ["-t"]["--list-tags"] ( "list all/matching tags" ) | Opt( config.showSuccessfulTests ) ["-s"]["--success"] ( "include successful tests in output" ) | Opt( config.shouldDebugBreak ) ["-b"]["--break"] ( "break into debugger on failure" ) | Opt( config.noThrow ) ["-e"]["--nothrow"] ( "skip exception tests" ) | Opt( config.showInvisibles ) ["-i"]["--invisibles"] ( "show invisibles (tabs, newlines)" ) | Opt( config.outputFilename, "filename" ) ["-o"]["--out"] ( "output filename" ) | Opt( config.reporterName, "name" ) ["-r"]["--reporter"] ( "reporter to use (defaults to console)" ) | Opt( config.name, "name" ) ["-n"]["--name"] ( "suite name" ) | Opt( [&]( bool ){ config.abortAfter = 1; } ) ["-a"]["--abort"] ( "abort at first failure" ) | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) ["-x"]["--abortx"] ( "abort after x failures" ) | Opt( setWarning, "warning name" ) ["-w"]["--warn"] ( "enable warnings" ) | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) ["-d"]["--durations"] ( "show test durations" ) | Opt( loadTestNamesFromFile, "filename" ) ["-f"]["--input-file"] ( "load test names to run from a file" ) | Opt( config.filenamesAsTags ) ["-#"]["--filenames-as-tags"] ( "adds a tag for the filename" ) | Opt( config.sectionsToRun, "section name" ) ["-c"]["--section"] ( "specify section to run" ) | Opt( setVerbosity, "quiet|normal|high" ) ["-v"]["--verbosity"] ( "set output verbosity" ) | Opt( config.listTestNamesOnly ) ["--list-test-names-only"] ( "list all/matching test cases names only" ) | Opt( config.listReporters ) ["--list-reporters"] ( "list all reporters" ) | Opt( setTestOrder, "decl|lex|rand" ) ["--order"] ( "test case order (defaults to decl)" ) | Opt( setRngSeed, "'time'|number" ) ["--rng-seed"] ( "set a specific seed for random numbers" ) | Opt( setColourUsage, "yes|no" ) ["--use-colour"] ( "should output be colourised" ) | Opt( config.libIdentify ) ["--libidentify"] ( "report name and version according to libidentify standard" ) | Opt( setWaitForKeypress, "start|exit|both" ) ["--wait-for-keypress"] ( "waits for a keypress before exiting" ) | Opt( config.benchmarkResolutionMultiple, "multiplier" ) ["--benchmark-resolution-multiple"] ( "multiple of clock resolution to run benchmarks" ) | Arg( config.testsOrTags, "test name|pattern|tags" ) ( "which test or tests to use" ); return cli; } } // end namespace Catch // end catch_commandline.cpp // start catch_common.cpp #include #include namespace Catch { bool SourceLineInfo::empty() const noexcept { return file[0] == '\0'; } bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); } bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); } std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ os << info.file << '(' << info.line << ')'; #else os << info.file << ':' << info.line; #endif return os; } std::string StreamEndStop::operator+() const { return std::string(); } NonCopyable::NonCopyable() = default; NonCopyable::~NonCopyable() = default; } // end catch_common.cpp // start catch_config.cpp // start catch_enforce.h #include #define CATCH_PREPARE_EXCEPTION( type, msg ) \ type( ( Catch::ReusableStringStream() << msg ).str() ) #define CATCH_INTERNAL_ERROR( msg ) \ throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); #define CATCH_ERROR( msg ) \ throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) #define CATCH_ENFORCE( condition, msg ) \ do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) // end catch_enforce.h namespace Catch { Config::Config( ConfigData const& data ) : m_data( data ), m_stream( openStream() ) { TestSpecParser parser(ITagAliasRegistry::get()); if (data.testsOrTags.empty()) { parser.parse("~[.]"); // All not hidden tests } else { m_hasTestFilters = true; for( auto const& testOrTags : data.testsOrTags ) parser.parse( testOrTags ); } m_testSpec = parser.testSpec(); } std::string const& Config::getFilename() const { return m_data.outputFilename ; } bool Config::listTests() const { return m_data.listTests; } bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } bool Config::listTags() const { return m_data.listTags; } bool Config::listReporters() const { return m_data.listReporters; } std::string Config::getProcessName() const { return m_data.processName; } std::string const& Config::getReporterName() const { return m_data.reporterName; } std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } TestSpec const& Config::testSpec() const { return m_testSpec; } bool Config::hasTestFilters() const { return m_hasTestFilters; } bool Config::showHelp() const { return m_data.showHelp; } // IConfig interface bool Config::allowThrows() const { return !m_data.noThrow; } std::ostream& Config::stream() const { return m_stream->stream(); } std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } unsigned int Config::rngSeed() const { return m_data.rngSeed; } int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } int Config::abortAfter() const { return m_data.abortAfter; } bool Config::showInvisibles() const { return m_data.showInvisibles; } Verbosity Config::verbosity() const { return m_data.verbosity; } IStream const* Config::openStream() { return Catch::makeStream(m_data.outputFilename); } } // end namespace Catch // end catch_config.cpp // start catch_console_colour.cpp #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wexit-time-destructors" #endif // start catch_errno_guard.h namespace Catch { class ErrnoGuard { public: ErrnoGuard(); ~ErrnoGuard(); private: int m_oldErrno; }; } // end catch_errno_guard.h #include namespace Catch { namespace { struct IColourImpl { virtual ~IColourImpl() = default; virtual void use( Colour::Code _colourCode ) = 0; }; struct NoColourImpl : IColourImpl { void use( Colour::Code ) {} static IColourImpl* instance() { static NoColourImpl s_instance; return &s_instance; } }; } // anon namespace } // namespace Catch #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) # ifdef CATCH_PLATFORM_WINDOWS # define CATCH_CONFIG_COLOUR_WINDOWS # else # define CATCH_CONFIG_COLOUR_ANSI # endif #endif #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// namespace Catch { namespace { class Win32ColourImpl : public IColourImpl { public: Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } virtual void use( Colour::Code _colourCode ) override { switch( _colourCode ) { case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); case Colour::Grey: return setTextAttribute( 0 ); case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); default: CATCH_ERROR( "Unknown colour requested" ); } } private: void setTextAttribute( WORD _textAttribute ) { SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); } HANDLE stdoutHandle; WORD originalForegroundAttributes; WORD originalBackgroundAttributes; }; IColourImpl* platformColourInstance() { static Win32ColourImpl s_instance; IConfigPtr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; if( colourMode == UseColour::Auto ) colourMode = UseColour::Yes; return colourMode == UseColour::Yes ? &s_instance : NoColourImpl::instance(); } } // end anon namespace } // end namespace Catch #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// #include namespace Catch { namespace { // use POSIX/ ANSI console terminal codes // Thanks to Adam Strzelecki for original contribution // (http://github.com/nanoant) // https://github.com/philsquared/Catch/pull/131 class PosixColourImpl : public IColourImpl { public: virtual void use( Colour::Code _colourCode ) override { switch( _colourCode ) { case Colour::None: case Colour::White: return setColour( "[0m" ); case Colour::Red: return setColour( "[0;31m" ); case Colour::Green: return setColour( "[0;32m" ); case Colour::Blue: return setColour( "[0;34m" ); case Colour::Cyan: return setColour( "[0;36m" ); case Colour::Yellow: return setColour( "[0;33m" ); case Colour::Grey: return setColour( "[1;30m" ); case Colour::LightGrey: return setColour( "[0;37m" ); case Colour::BrightRed: return setColour( "[1;31m" ); case Colour::BrightGreen: return setColour( "[1;32m" ); case Colour::BrightWhite: return setColour( "[1;37m" ); case Colour::BrightYellow: return setColour( "[1;33m" ); case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); } } static IColourImpl* instance() { static PosixColourImpl s_instance; return &s_instance; } private: void setColour( const char* _escapeCode ) { Catch::cout() << '\033' << _escapeCode; } }; bool useColourOnPlatform() { return #ifdef CATCH_PLATFORM_MAC !isDebuggerActive() && #endif #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) isatty(STDOUT_FILENO) #else false #endif ; } IColourImpl* platformColourInstance() { ErrnoGuard guard; IConfigPtr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; if( colourMode == UseColour::Auto ) colourMode = useColourOnPlatform() ? UseColour::Yes : UseColour::No; return colourMode == UseColour::Yes ? PosixColourImpl::instance() : NoColourImpl::instance(); } } // end anon namespace } // end namespace Catch #else // not Windows or ANSI /////////////////////////////////////////////// namespace Catch { static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } } // end namespace Catch #endif // Windows/ ANSI/ None namespace Catch { Colour::Colour( Code _colourCode ) { use( _colourCode ); } Colour::Colour( Colour&& rhs ) noexcept { m_moved = rhs.m_moved; rhs.m_moved = true; } Colour& Colour::operator=( Colour&& rhs ) noexcept { m_moved = rhs.m_moved; rhs.m_moved = true; return *this; } Colour::~Colour(){ if( !m_moved ) use( None ); } void Colour::use( Code _colourCode ) { static IColourImpl* impl = platformColourInstance(); impl->use( _colourCode ); } std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } } // end namespace Catch #if defined(__clang__) # pragma clang diagnostic pop #endif // end catch_console_colour.cpp // start catch_context.cpp namespace Catch { class Context : public IMutableContext, NonCopyable { public: // IContext virtual IResultCapture* getResultCapture() override { return m_resultCapture; } virtual IRunner* getRunner() override { return m_runner; } virtual IConfigPtr const& getConfig() const override { return m_config; } virtual ~Context() override; public: // IMutableContext virtual void setResultCapture( IResultCapture* resultCapture ) override { m_resultCapture = resultCapture; } virtual void setRunner( IRunner* runner ) override { m_runner = runner; } virtual void setConfig( IConfigPtr const& config ) override { m_config = config; } friend IMutableContext& getCurrentMutableContext(); private: IConfigPtr m_config; IRunner* m_runner = nullptr; IResultCapture* m_resultCapture = nullptr; }; IMutableContext *IMutableContext::currentContext = nullptr; void IMutableContext::createContext() { currentContext = new Context(); } void cleanUpContext() { delete IMutableContext::currentContext; IMutableContext::currentContext = nullptr; } IContext::~IContext() = default; IMutableContext::~IMutableContext() = default; Context::~Context() = default; } // end catch_context.cpp // start catch_debug_console.cpp // start catch_debug_console.h #include namespace Catch { void writeToDebugConsole( std::string const& text ); } // end catch_debug_console.h #ifdef CATCH_PLATFORM_WINDOWS namespace Catch { void writeToDebugConsole( std::string const& text ) { ::OutputDebugStringA( text.c_str() ); } } #else namespace Catch { void writeToDebugConsole( std::string const& text ) { // !TBD: Need a version for Mac/ XCode and other IDEs Catch::cout() << text; } } #endif // Platform // end catch_debug_console.cpp // start catch_debugger.cpp #ifdef CATCH_PLATFORM_MAC # include # include # include # include # include # include # include namespace Catch { // The following function is taken directly from the following technical note: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html // Returns true if the current process is being debugged (either // running under the debugger or has a debugger attached post facto). bool isDebuggerActive(){ int mib[4]; struct kinfo_proc info; std::size_t size; // Initialize the flags so that, if sysctl fails for some bizarre // reason, we get a predictable result. info.kp_proc.p_flag = 0; // Initialize mib, which tells sysctl the info we want, in this case // we're looking for information about a specific process ID. mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = getpid(); // Call sysctl. size = sizeof(info); if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } // We're being debugged if the P_TRACED flag is set. return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); } } // namespace Catch #elif defined(CATCH_PLATFORM_LINUX) #include #include namespace Catch{ // The standard POSIX way of detecting a debugger is to attempt to // ptrace() the process, but this needs to be done from a child and not // this process itself to still allow attaching to this process later // if wanted, so is rather heavy. Under Linux we have the PID of the // "debugger" (which doesn't need to be gdb, of course, it could also // be strace, for example) in /proc/$PID/status, so just get it from // there instead. bool isDebuggerActive(){ // Libstdc++ has a bug, where std::ifstream sets errno to 0 // This way our users can properly assert over errno values ErrnoGuard guard; std::ifstream in("/proc/self/status"); for( std::string line; std::getline(in, line); ) { static const int PREFIX_LEN = 11; if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { // We're traced if the PID is not 0 and no other PID starts // with 0 digit, so it's enough to check for just a single // character. return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; } } return false; } } // namespace Catch #elif defined(_MSC_VER) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #elif defined(__MINGW32__) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #else namespace Catch { bool isDebuggerActive() { return false; } } #endif // Platform // end catch_debugger.cpp // start catch_decomposer.cpp namespace Catch { ITransientExpression::~ITransientExpression() = default; void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { if( lhs.size() + rhs.size() < 40 && lhs.find('\n') == std::string::npos && rhs.find('\n') == std::string::npos ) os << lhs << " " << op << " " << rhs; else os << lhs << "\n" << op << "\n" << rhs; } } // end catch_decomposer.cpp // start catch_errno_guard.cpp #include namespace Catch { ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } } // end catch_errno_guard.cpp // start catch_exception_translator_registry.cpp // start catch_exception_translator_registry.h #include #include #include namespace Catch { class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { public: ~ExceptionTranslatorRegistry(); virtual void registerTranslator( const IExceptionTranslator* translator ); virtual std::string translateActiveException() const override; std::string tryTranslators() const; private: std::vector> m_translators; }; } // end catch_exception_translator_registry.h #ifdef __OBJC__ #import "Foundation/Foundation.h" #endif namespace Catch { ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { } void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { m_translators.push_back( std::unique_ptr( translator ) ); } std::string ExceptionTranslatorRegistry::translateActiveException() const { try { #ifdef __OBJC__ // In Objective-C try objective-c exceptions first @try { return tryTranslators(); } @catch (NSException *exception) { return Catch::Detail::stringify( [exception description] ); } #else // Compiling a mixed mode project with MSVC means that CLR // exceptions will be caught in (...) as well. However, these // do not fill-in std::current_exception and thus lead to crash // when attempting rethrow. // /EHa switch also causes structured exceptions to be caught // here, but they fill-in current_exception properly, so // at worst the output should be a little weird, instead of // causing a crash. if (std::current_exception() == nullptr) { return "Non C++ exception. Possibly a CLR exception."; } return tryTranslators(); #endif } catch( TestFailureException& ) { std::rethrow_exception(std::current_exception()); } catch( std::exception& ex ) { return ex.what(); } catch( std::string& msg ) { return msg; } catch( const char* msg ) { return msg; } catch(...) { return "Unknown exception"; } } std::string ExceptionTranslatorRegistry::tryTranslators() const { if( m_translators.empty() ) std::rethrow_exception(std::current_exception()); else return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); } } // end catch_exception_translator_registry.cpp // start catch_fatal_condition.cpp #if defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) namespace { // Report the error condition void reportFatal( char const * const message ) { Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); } } #endif // signals/SEH handling #if defined( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { struct SignalDefs { DWORD id; const char* name; }; // There is no 1-1 mapping between signals and windows exceptions. // Windows can easily distinguish between SO and SigSegV, // but SigInt, SigTerm, etc are handled differently. static SignalDefs signalDefs[] = { { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, }; LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { for (auto const& def : signalDefs) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { reportFatal(def.name); } } // If its not an exception we care about, pass it along. // This stops us from eating debugger breaks etc. return EXCEPTION_CONTINUE_SEARCH; } FatalConditionHandler::FatalConditionHandler() { isSet = true; // 32k seems enough for Catch to handle stack overflow, // but the value was found experimentally, so there is no strong guarantee guaranteeSize = 32 * 1024; exceptionHandlerHandle = nullptr; // Register as first handler in current chain exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); // Pass in guarantee size to be filled SetThreadStackGuarantee(&guaranteeSize); } void FatalConditionHandler::reset() { if (isSet) { RemoveVectoredExceptionHandler(exceptionHandlerHandle); SetThreadStackGuarantee(&guaranteeSize); exceptionHandlerHandle = nullptr; isSet = false; } } FatalConditionHandler::~FatalConditionHandler() { reset(); } bool FatalConditionHandler::isSet = false; ULONG FatalConditionHandler::guaranteeSize = 0; PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; } // namespace Catch #elif defined( CATCH_CONFIG_POSIX_SIGNALS ) namespace Catch { struct SignalDefs { int id; const char* name; }; // 32kb for the alternate stack seems to be sufficient. However, this value // is experimentally determined, so that's not guaranteed. constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; static SignalDefs signalDefs[] = { { SIGINT, "SIGINT - Terminal interrupt signal" }, { SIGILL, "SIGILL - Illegal instruction signal" }, { SIGFPE, "SIGFPE - Floating point error signal" }, { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, { SIGTERM, "SIGTERM - Termination request signal" }, { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } }; void FatalConditionHandler::handleSignal( int sig ) { char const * name = ""; for (auto const& def : signalDefs) { if (sig == def.id) { name = def.name; break; } } reset(); reportFatal(name); raise( sig ); } FatalConditionHandler::FatalConditionHandler() { isSet = true; stack_t sigStack; sigStack.ss_sp = altStackMem; sigStack.ss_size = sigStackSize; sigStack.ss_flags = 0; sigaltstack(&sigStack, &oldSigStack); struct sigaction sa = { }; sa.sa_handler = handleSignal; sa.sa_flags = SA_ONSTACK; for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); } } FatalConditionHandler::~FatalConditionHandler() { reset(); } void FatalConditionHandler::reset() { if( isSet ) { // Set signals back to previous values -- hopefully nobody overwrote them in the meantime for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); } // Return the old stack sigaltstack(&oldSigStack, nullptr); isSet = false; } } bool FatalConditionHandler::isSet = false; struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; stack_t FatalConditionHandler::oldSigStack = {}; char FatalConditionHandler::altStackMem[sigStackSize] = {}; } // namespace Catch #else namespace Catch { void FatalConditionHandler::reset() {} } #endif // signals/SEH handling #if defined(__GNUC__) # pragma GCC diagnostic pop #endif // end catch_fatal_condition.cpp // start catch_interfaces_capture.cpp namespace Catch { IResultCapture::~IResultCapture() = default; } // end catch_interfaces_capture.cpp // start catch_interfaces_config.cpp namespace Catch { IConfig::~IConfig() = default; } // end catch_interfaces_config.cpp // start catch_interfaces_exception.cpp namespace Catch { IExceptionTranslator::~IExceptionTranslator() = default; IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; } // end catch_interfaces_exception.cpp // start catch_interfaces_registry_hub.cpp namespace Catch { IRegistryHub::~IRegistryHub() = default; IMutableRegistryHub::~IMutableRegistryHub() = default; } // end catch_interfaces_registry_hub.cpp // start catch_interfaces_reporter.cpp // start catch_reporter_listening.h namespace Catch { class ListeningReporter : public IStreamingReporter { using Reporters = std::vector; Reporters m_listeners; IStreamingReporterPtr m_reporter = nullptr; public: void addListener( IStreamingReporterPtr&& listener ); void addReporter( IStreamingReporterPtr&& reporter ); public: // IStreamingReporter ReporterPreferences getPreferences() const override; void noMatchingTestCases( std::string const& spec ) override; static std::set getSupportedVerbosities(); void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; void testRunStarting( TestRunInfo const& testRunInfo ) override; void testGroupStarting( GroupInfo const& groupInfo ) override; void testCaseStarting( TestCaseInfo const& testInfo ) override; void sectionStarting( SectionInfo const& sectionInfo ) override; void assertionStarting( AssertionInfo const& assertionInfo ) override; // The return value indicates if the messages buffer should be cleared: bool assertionEnded( AssertionStats const& assertionStats ) override; void sectionEnded( SectionStats const& sectionStats ) override; void testCaseEnded( TestCaseStats const& testCaseStats ) override; void testGroupEnded( TestGroupStats const& testGroupStats ) override; void testRunEnded( TestRunStats const& testRunStats ) override; void skipTest( TestCaseInfo const& testInfo ) override; bool isMulti() const override; }; } // end namespace Catch // end catch_reporter_listening.h namespace Catch { ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} std::ostream& ReporterConfig::stream() const { return *m_stream; } IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} GroupInfo::GroupInfo( std::string const& _name, std::size_t _groupIndex, std::size_t _groupsCount ) : name( _name ), groupIndex( _groupIndex ), groupsCounts( _groupsCount ) {} AssertionStats::AssertionStats( AssertionResult const& _assertionResult, std::vector const& _infoMessages, Totals const& _totals ) : assertionResult( _assertionResult ), infoMessages( _infoMessages ), totals( _totals ) { assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; if( assertionResult.hasMessage() ) { // Copy message into messages list. // !TBD This should have been done earlier, somewhere MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); builder << assertionResult.getMessage(); builder.m_info.message = builder.m_stream.str(); infoMessages.push_back( builder.m_info ); } } AssertionStats::~AssertionStats() = default; SectionStats::SectionStats( SectionInfo const& _sectionInfo, Counts const& _assertions, double _durationInSeconds, bool _missingAssertions ) : sectionInfo( _sectionInfo ), assertions( _assertions ), durationInSeconds( _durationInSeconds ), missingAssertions( _missingAssertions ) {} SectionStats::~SectionStats() = default; TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, std::string const& _stdOut, std::string const& _stdErr, bool _aborting ) : testInfo( _testInfo ), totals( _totals ), stdOut( _stdOut ), stdErr( _stdErr ), aborting( _aborting ) {} TestCaseStats::~TestCaseStats() = default; TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, Totals const& _totals, bool _aborting ) : groupInfo( _groupInfo ), totals( _totals ), aborting( _aborting ) {} TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) : groupInfo( _groupInfo ), aborting( false ) {} TestGroupStats::~TestGroupStats() = default; TestRunStats::TestRunStats( TestRunInfo const& _runInfo, Totals const& _totals, bool _aborting ) : runInfo( _runInfo ), totals( _totals ), aborting( _aborting ) {} TestRunStats::~TestRunStats() = default; void IStreamingReporter::fatalErrorEncountered( StringRef ) {} bool IStreamingReporter::isMulti() const { return false; } IReporterFactory::~IReporterFactory() = default; IReporterRegistry::~IReporterRegistry() = default; } // end namespace Catch // end catch_interfaces_reporter.cpp // start catch_interfaces_runner.cpp namespace Catch { IRunner::~IRunner() = default; } // end catch_interfaces_runner.cpp // start catch_interfaces_testcase.cpp namespace Catch { ITestInvoker::~ITestInvoker() = default; ITestCaseRegistry::~ITestCaseRegistry() = default; } // end catch_interfaces_testcase.cpp // start catch_leak_detector.cpp #ifdef CATCH_CONFIG_WINDOWS_CRTDBG #include namespace Catch { LeakDetector::LeakDetector() { int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); flag |= _CRTDBG_LEAK_CHECK_DF; flag |= _CRTDBG_ALLOC_MEM_DF; _CrtSetDbgFlag(flag); _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); // Change this to leaking allocation's number to break there _CrtSetBreakAlloc(-1); } } #else Catch::LeakDetector::LeakDetector() {} #endif // end catch_leak_detector.cpp // start catch_list.cpp // start catch_list.h #include namespace Catch { std::size_t listTests( Config const& config ); std::size_t listTestsNamesOnly( Config const& config ); struct TagInfo { void add( std::string const& spelling ); std::string all() const; std::set spellings; std::size_t count = 0; }; std::size_t listTags( Config const& config ); std::size_t listReporters( Config const& /*config*/ ); Option list( Config const& config ); } // end namespace Catch // end catch_list.h // start catch_text.h namespace Catch { using namespace clara::TextFlow; } // end catch_text.h #include #include #include namespace Catch { std::size_t listTests( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.hasTestFilters() ) Catch::cout() << "Matching test cases:\n"; else { Catch::cout() << "All available test cases:\n"; } auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( auto const& testCaseInfo : matchedTestCases ) { Colour::Code colour = testCaseInfo.isHidden() ? Colour::SecondaryText : Colour::None; Colour colourGuard( colour ); Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; if( config.verbosity() >= Verbosity::High ) { Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; std::string description = testCaseInfo.description; if( description.empty() ) description = "(NO DESCRIPTION)"; Catch::cout() << Column( description ).indent(4) << std::endl; } if( !testCaseInfo.tags.empty() ) Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; } if( !config.hasTestFilters() ) Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; else Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; return matchedTestCases.size(); } std::size_t listTestsNamesOnly( Config const& config ) { TestSpec testSpec = config.testSpec(); std::size_t matchedTests = 0; std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( auto const& testCaseInfo : matchedTestCases ) { matchedTests++; if( startsWith( testCaseInfo.name, '#' ) ) Catch::cout() << '"' << testCaseInfo.name << '"'; else Catch::cout() << testCaseInfo.name; if ( config.verbosity() >= Verbosity::High ) Catch::cout() << "\t@" << testCaseInfo.lineInfo; Catch::cout() << std::endl; } return matchedTests; } void TagInfo::add( std::string const& spelling ) { ++count; spellings.insert( spelling ); } std::string TagInfo::all() const { std::string out; for( auto const& spelling : spellings ) out += "[" + spelling + "]"; return out; } std::size_t listTags( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.hasTestFilters() ) Catch::cout() << "Tags for matching test cases:\n"; else { Catch::cout() << "All available tags:\n"; } std::map tagCounts; std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( auto const& testCase : matchedTestCases ) { for( auto const& tagName : testCase.getTestCaseInfo().tags ) { std::string lcaseTagName = toLower( tagName ); auto countIt = tagCounts.find( lcaseTagName ); if( countIt == tagCounts.end() ) countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; countIt->second.add( tagName ); } } for( auto const& tagCount : tagCounts ) { ReusableStringStream rss; rss << " " << std::setw(2) << tagCount.second.count << " "; auto str = rss.str(); auto wrapper = Column( tagCount.second.all() ) .initialIndent( 0 ) .indent( str.size() ) .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); Catch::cout() << str << wrapper << '\n'; } Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; return tagCounts.size(); } std::size_t listReporters( Config const& /*config*/ ) { Catch::cout() << "Available reporters:\n"; IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); std::size_t maxNameLen = 0; for( auto const& factoryKvp : factories ) maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); for( auto const& factoryKvp : factories ) { Catch::cout() << Column( factoryKvp.first + ":" ) .indent(2) .width( 5+maxNameLen ) + Column( factoryKvp.second->getDescription() ) .initialIndent(0) .indent(2) .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) << "\n"; } Catch::cout() << std::endl; return factories.size(); } Option list( Config const& config ) { Option listedCount; if( config.listTests() ) listedCount = listedCount.valueOr(0) + listTests( config ); if( config.listTestNamesOnly() ) listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); if( config.listTags() ) listedCount = listedCount.valueOr(0) + listTags( config ); if( config.listReporters() ) listedCount = listedCount.valueOr(0) + listReporters( config ); return listedCount; } } // end namespace Catch // end catch_list.cpp // start catch_matchers.cpp namespace Catch { namespace Matchers { namespace Impl { std::string MatcherUntypedBase::toString() const { if( m_cachedToString.empty() ) m_cachedToString = describe(); return m_cachedToString; } MatcherUntypedBase::~MatcherUntypedBase() = default; } // namespace Impl } // namespace Matchers using namespace Matchers; using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.cpp // start catch_matchers_floating.cpp // start catch_to_string.hpp #include namespace Catch { template std::string to_string(T const& t) { #if defined(CATCH_CONFIG_CPP11_TO_STRING) return std::to_string(t); #else ReusableStringStream rss; rss << t; return rss.str(); #endif } } // end namespace Catch // end catch_to_string.hpp #include #include #include #include namespace Catch { namespace Matchers { namespace Floating { enum class FloatingPointKind : uint8_t { Float, Double }; } } } namespace { template struct Converter; template <> struct Converter { static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); Converter(float f) { std::memcpy(&i, &f, sizeof(f)); } int32_t i; }; template <> struct Converter { static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); Converter(double d) { std::memcpy(&i, &d, sizeof(d)); } int64_t i; }; template auto convert(T t) -> Converter { return Converter(t); } template bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { // Comparison with NaN should always be false. // This way we can rule it out before getting into the ugly details if (std::isnan(lhs) || std::isnan(rhs)) { return false; } auto lc = convert(lhs); auto rc = convert(rhs); if ((lc.i < 0) != (rc.i < 0)) { // Potentially we can have +0 and -0 return lhs == rhs; } auto ulpDiff = std::abs(lc.i - rc.i); return ulpDiff <= maxUlpDiff; } } namespace Catch { namespace Matchers { namespace Floating { WithinAbsMatcher::WithinAbsMatcher(double target, double margin) :m_target{ target }, m_margin{ margin } { if (m_margin < 0) { throw std::domain_error("Allowed margin difference has to be >= 0"); } } // Performs equivalent check of std::fabs(lhs - rhs) <= margin // But without the subtraction to allow for INFINITY in comparison bool WithinAbsMatcher::match(double const& matchee) const { return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); } std::string WithinAbsMatcher::describe() const { return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); } WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { if (m_ulps < 0) { throw std::domain_error("Allowed ulp difference has to be >= 0"); } } bool WithinUlpsMatcher::match(double const& matchee) const { switch (m_type) { case FloatingPointKind::Float: return almostEqualUlps(static_cast(matchee), static_cast(m_target), m_ulps); case FloatingPointKind::Double: return almostEqualUlps(matchee, m_target, m_ulps); default: throw std::domain_error("Unknown FloatingPointKind value"); } } std::string WithinUlpsMatcher::describe() const { return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); } }// namespace Floating Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); } Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); } Floating::WithinAbsMatcher WithinAbs(double target, double margin) { return Floating::WithinAbsMatcher(target, margin); } } // namespace Matchers } // namespace Catch // end catch_matchers_floating.cpp // start catch_matchers_generic.cpp std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { if (desc.empty()) { return "matches undescribed predicate"; } else { return "matches predicate: \"" + desc + '"'; } } // end catch_matchers_generic.cpp // start catch_matchers_string.cpp #include namespace Catch { namespace Matchers { namespace StdString { CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) : m_caseSensitivity( caseSensitivity ), m_str( adjustString( str ) ) {} std::string CasedString::adjustString( std::string const& str ) const { return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; } std::string CasedString::caseSensitivitySuffix() const { return m_caseSensitivity == CaseSensitive::No ? " (case insensitive)" : std::string(); } StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) : m_comparator( comparator ), m_operation( operation ) { } std::string StringMatcherBase::describe() const { std::string description; description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + m_comparator.caseSensitivitySuffix().size()); description += m_operation; description += ": \""; description += m_comparator.m_str; description += "\""; description += m_comparator.caseSensitivitySuffix(); return description; } EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} bool EqualsMatcher::match( std::string const& source ) const { return m_comparator.adjustString( source ) == m_comparator.m_str; } ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} bool ContainsMatcher::match( std::string const& source ) const { return contains( m_comparator.adjustString( source ), m_comparator.m_str ); } StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} bool StartsWithMatcher::match( std::string const& source ) const { return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); } EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} bool EndsWithMatcher::match( std::string const& source ) const { return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); } RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} bool RegexMatcher::match(std::string const& matchee) const { auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway if (m_caseSensitivity == CaseSensitive::Choice::No) { flags |= std::regex::icase; } auto reg = std::regex(m_regex, flags); return std::regex_match(matchee, reg); } std::string RegexMatcher::describe() const { return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); } } // namespace StdString StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); } StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); } StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); } StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); } StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { return StdString::RegexMatcher(regex, caseSensitivity); } } // namespace Matchers } // namespace Catch // end catch_matchers_string.cpp // start catch_message.cpp // start catch_uncaught_exceptions.h namespace Catch { bool uncaught_exceptions(); } // end namespace Catch // end catch_uncaught_exceptions.h namespace Catch { MessageInfo::MessageInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ) : macroName( _macroName ), lineInfo( _lineInfo ), type( _type ), sequence( ++globalCount ) {} bool MessageInfo::operator==( MessageInfo const& other ) const { return sequence == other.sequence; } bool MessageInfo::operator<( MessageInfo const& other ) const { return sequence < other.sequence; } // This may need protecting if threading support is added unsigned int MessageInfo::globalCount = 0; //////////////////////////////////////////////////////////////////////////// Catch::MessageBuilder::MessageBuilder( std::string const& macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ) :m_info(macroName, lineInfo, type) {} //////////////////////////////////////////////////////////////////////////// ScopedMessage::ScopedMessage( MessageBuilder const& builder ) : m_info( builder.m_info ) { m_info.message = builder.m_stream.str(); getResultCapture().pushScopedMessage( m_info ); } ScopedMessage::~ScopedMessage() { if ( !uncaught_exceptions() ){ getResultCapture().popScopedMessage(m_info); } } } // end namespace Catch // end catch_message.cpp // start catch_output_redirect.cpp // start catch_output_redirect.h #ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H #define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H #include #include #include namespace Catch { class RedirectedStream { std::ostream& m_originalStream; std::ostream& m_redirectionStream; std::streambuf* m_prevBuf; public: RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); ~RedirectedStream(); }; class RedirectedStdOut { ReusableStringStream m_rss; RedirectedStream m_cout; public: RedirectedStdOut(); auto str() const -> std::string; }; // StdErr has two constituent streams in C++, std::cerr and std::clog // This means that we need to redirect 2 streams into 1 to keep proper // order of writes class RedirectedStdErr { ReusableStringStream m_rss; RedirectedStream m_cerr; RedirectedStream m_clog; public: RedirectedStdErr(); auto str() const -> std::string; }; // Windows's implementation of std::tmpfile is terrible (it tries // to create a file inside system folder, thus requiring elevated // privileges for the binary), so we have to use tmpnam(_s) and // create the file ourselves there. class TempFile { public: TempFile(TempFile const&) = delete; TempFile& operator=(TempFile const&) = delete; TempFile(TempFile&&) = delete; TempFile& operator=(TempFile&&) = delete; TempFile(); ~TempFile(); std::FILE* getFile(); std::string getContents(); private: std::FILE* m_file = nullptr; #if defined(_MSC_VER) char m_buffer[L_tmpnam] = { 0 }; #endif }; class OutputRedirect { public: OutputRedirect(OutputRedirect const&) = delete; OutputRedirect& operator=(OutputRedirect const&) = delete; OutputRedirect(OutputRedirect&&) = delete; OutputRedirect& operator=(OutputRedirect&&) = delete; OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); ~OutputRedirect(); private: int m_originalStdout = -1; int m_originalStderr = -1; TempFile m_stdoutFile; TempFile m_stderrFile; std::string& m_stdoutDest; std::string& m_stderrDest; }; } // end namespace Catch #endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H // end catch_output_redirect.h #include #include #include #include #include #if defined(_MSC_VER) #include //_dup and _dup2 #define dup _dup #define dup2 _dup2 #define fileno _fileno #else #include // dup and dup2 #endif namespace Catch { RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) : m_originalStream( originalStream ), m_redirectionStream( redirectionStream ), m_prevBuf( m_originalStream.rdbuf() ) { m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); } RedirectedStream::~RedirectedStream() { m_originalStream.rdbuf( m_prevBuf ); } RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } RedirectedStdErr::RedirectedStdErr() : m_cerr( Catch::cerr(), m_rss.get() ), m_clog( Catch::clog(), m_rss.get() ) {} auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } #if defined(_MSC_VER) TempFile::TempFile() { if (tmpnam_s(m_buffer)) { throw std::runtime_error("Could not get a temp filename"); } if (fopen_s(&m_file, m_buffer, "w")) { char buffer[100]; if (strerror_s(buffer, errno)) { throw std::runtime_error("Could not translate errno to string"); } throw std::runtime_error("Could not open the temp file: " + std::string(m_buffer) + buffer); } } #else TempFile::TempFile() { m_file = std::tmpfile(); if (!m_file) { throw std::runtime_error("Could not create a temp file."); } } #endif TempFile::~TempFile() { // TBD: What to do about errors here? std::fclose(m_file); // We manually create the file on Windows only, on Linux // it will be autodeleted #if defined(_MSC_VER) std::remove(m_buffer); #endif } FILE* TempFile::getFile() { return m_file; } std::string TempFile::getContents() { std::stringstream sstr; char buffer[100] = {}; std::rewind(m_file); while (std::fgets(buffer, sizeof(buffer), m_file)) { sstr << buffer; } return sstr.str(); } OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : m_originalStdout(dup(1)), m_originalStderr(dup(2)), m_stdoutDest(stdout_dest), m_stderrDest(stderr_dest) { dup2(fileno(m_stdoutFile.getFile()), 1); dup2(fileno(m_stderrFile.getFile()), 2); } OutputRedirect::~OutputRedirect() { Catch::cout() << std::flush; fflush(stdout); // Since we support overriding these streams, we flush cerr // even though std::cerr is unbuffered Catch::cerr() << std::flush; Catch::clog() << std::flush; fflush(stderr); dup2(m_originalStdout, 1); dup2(m_originalStderr, 2); m_stdoutDest += m_stdoutFile.getContents(); m_stderrDest += m_stderrFile.getContents(); } } // namespace Catch #if defined(_MSC_VER) #undef dup #undef dup2 #undef fileno #endif // end catch_output_redirect.cpp // start catch_random_number_generator.cpp // start catch_random_number_generator.h #include namespace Catch { struct IConfig; void seedRng( IConfig const& config ); unsigned int rngSeed(); struct RandomNumberGenerator { using result_type = unsigned int; static constexpr result_type (min)() { return 0; } static constexpr result_type (max)() { return 1000000; } result_type operator()( result_type n ) const; result_type operator()() const; template static void shuffle( V& vector ) { RandomNumberGenerator rng; std::shuffle( vector.begin(), vector.end(), rng ); } }; } // end catch_random_number_generator.h #include namespace Catch { void seedRng( IConfig const& config ) { if( config.rngSeed() != 0 ) std::srand( config.rngSeed() ); } unsigned int rngSeed() { return getCurrentContext().getConfig()->rngSeed(); } RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const { return std::rand() % n; } RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const { return std::rand() % (max)(); } } // end catch_random_number_generator.cpp // start catch_registry_hub.cpp // start catch_test_case_registry_impl.h #include #include #include #include namespace Catch { class TestCase; struct IConfig; std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); void enforceNoDuplicateTestCases( std::vector const& functions ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); class TestRegistry : public ITestCaseRegistry { public: virtual ~TestRegistry() = default; virtual void registerTest( TestCase const& testCase ); std::vector const& getAllTests() const override; std::vector const& getAllTestsSorted( IConfig const& config ) const override; private: std::vector m_functions; mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; mutable std::vector m_sortedFunctions; std::size_t m_unnamedCount = 0; std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised }; /////////////////////////////////////////////////////////////////////////// class TestInvokerAsFunction : public ITestInvoker { void(*m_testAsFunction)(); public: TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; void invoke() const override; }; std::string extractClassName( StringRef const& classOrQualifiedMethodName ); /////////////////////////////////////////////////////////////////////////// } // end namespace Catch // end catch_test_case_registry_impl.h // start catch_reporter_registry.h #include namespace Catch { class ReporterRegistry : public IReporterRegistry { public: ~ReporterRegistry() override; IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); void registerListener( IReporterFactoryPtr const& factory ); FactoryMap const& getFactories() const override; Listeners const& getListeners() const override; private: FactoryMap m_factories; Listeners m_listeners; }; } // end catch_reporter_registry.h // start catch_tag_alias_registry.h // start catch_tag_alias.h #include namespace Catch { struct TagAlias { TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); std::string tag; SourceLineInfo lineInfo; }; } // end namespace Catch // end catch_tag_alias.h #include namespace Catch { class TagAliasRegistry : public ITagAliasRegistry { public: ~TagAliasRegistry() override; TagAlias const* find( std::string const& alias ) const override; std::string expandAliases( std::string const& unexpandedTestSpec ) const override; void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); private: std::map m_registry; }; } // end namespace Catch // end catch_tag_alias_registry.h // start catch_startup_exception_registry.h #include #include namespace Catch { class StartupExceptionRegistry { public: void add(std::exception_ptr const& exception) noexcept; std::vector const& getExceptions() const noexcept; private: std::vector m_exceptions; }; } // end namespace Catch // end catch_startup_exception_registry.h namespace Catch { namespace { class RegistryHub : public IRegistryHub, public IMutableRegistryHub, private NonCopyable { public: // IRegistryHub RegistryHub() = default; IReporterRegistry const& getReporterRegistry() const override { return m_reporterRegistry; } ITestCaseRegistry const& getTestCaseRegistry() const override { return m_testCaseRegistry; } IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override { return m_exceptionTranslatorRegistry; } ITagAliasRegistry const& getTagAliasRegistry() const override { return m_tagAliasRegistry; } StartupExceptionRegistry const& getStartupExceptionRegistry() const override { return m_exceptionRegistry; } public: // IMutableRegistryHub void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { m_reporterRegistry.registerReporter( name, factory ); } void registerListener( IReporterFactoryPtr const& factory ) override { m_reporterRegistry.registerListener( factory ); } void registerTest( TestCase const& testInfo ) override { m_testCaseRegistry.registerTest( testInfo ); } void registerTranslator( const IExceptionTranslator* translator ) override { m_exceptionTranslatorRegistry.registerTranslator( translator ); } void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { m_tagAliasRegistry.add( alias, tag, lineInfo ); } void registerStartupException() noexcept override { m_exceptionRegistry.add(std::current_exception()); } private: TestRegistry m_testCaseRegistry; ReporterRegistry m_reporterRegistry; ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; TagAliasRegistry m_tagAliasRegistry; StartupExceptionRegistry m_exceptionRegistry; }; // Single, global, instance RegistryHub*& getTheRegistryHub() { static RegistryHub* theRegistryHub = nullptr; if( !theRegistryHub ) theRegistryHub = new RegistryHub(); return theRegistryHub; } } IRegistryHub& getRegistryHub() { return *getTheRegistryHub(); } IMutableRegistryHub& getMutableRegistryHub() { return *getTheRegistryHub(); } void cleanUp() { delete getTheRegistryHub(); getTheRegistryHub() = nullptr; cleanUpContext(); ReusableStringStream::cleanup(); } std::string translateActiveException() { return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); } } // end namespace Catch // end catch_registry_hub.cpp // start catch_reporter_registry.cpp namespace Catch { ReporterRegistry::~ReporterRegistry() = default; IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { auto it = m_factories.find( name ); if( it == m_factories.end() ) return nullptr; return it->second->create( ReporterConfig( config ) ); } void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { m_factories.emplace(name, factory); } void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { m_listeners.push_back( factory ); } IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { return m_factories; } IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { return m_listeners; } } // end catch_reporter_registry.cpp // start catch_result_type.cpp namespace Catch { bool isOk( ResultWas::OfType resultType ) { return ( resultType & ResultWas::FailureBit ) == 0; } bool isJustInfo( int flags ) { return flags == ResultWas::Info; } ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { return static_cast( static_cast( lhs ) | static_cast( rhs ) ); } bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } } // end namespace Catch // end catch_result_type.cpp // start catch_run_context.cpp #include #include #include namespace Catch { RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) : m_runInfo(_config->name()), m_context(getCurrentMutableContext()), m_config(_config), m_reporter(std::move(reporter)), m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, m_includeSuccessfulResults( m_config->includeSuccessfulResults() ) { m_context.setRunner(this); m_context.setConfig(m_config); m_context.setResultCapture(this); m_reporter->testRunStarting(m_runInfo); } RunContext::~RunContext() { m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); } void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); } void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); } Totals RunContext::runTest(TestCase const& testCase) { Totals prevTotals = m_totals; std::string redirectedCout; std::string redirectedCerr; auto const& testInfo = testCase.getTestCaseInfo(); m_reporter->testCaseStarting(testInfo); m_activeTestCase = &testCase; ITracker& rootTracker = m_trackerContext.startRun(); assert(rootTracker.isSectionTracker()); static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); do { m_trackerContext.startCycle(); m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); runCurrentTest(redirectedCout, redirectedCerr); } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); Totals deltaTotals = m_totals.delta(prevTotals); if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { deltaTotals.assertions.failed++; deltaTotals.testCases.passed--; deltaTotals.testCases.failed++; } m_totals.testCases += deltaTotals.testCases; m_reporter->testCaseEnded(TestCaseStats(testInfo, deltaTotals, redirectedCout, redirectedCerr, aborting())); m_activeTestCase = nullptr; m_testCaseTracker = nullptr; return deltaTotals; } IConfigPtr RunContext::config() const { return m_config; } IStreamingReporter& RunContext::reporter() const { return *m_reporter; } void RunContext::assertionEnded(AssertionResult const & result) { if (result.getResultType() == ResultWas::Ok) { m_totals.assertions.passed++; m_lastAssertionPassed = true; } else if (!result.isOk()) { m_lastAssertionPassed = false; if( m_activeTestCase->getTestCaseInfo().okToFail() ) m_totals.assertions.failedButOk++; else m_totals.assertions.failed++; } else { m_lastAssertionPassed = true; } // We have no use for the return value (whether messages should be cleared), because messages were made scoped // and should be let to clear themselves out. static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); // Reset working state resetAssertionInfo(); m_lastResult = result; } void RunContext::resetAssertionInfo() { m_lastAssertionInfo.macroName = StringRef(); m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; } bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); if (!sectionTracker.isOpen()) return false; m_activeSections.push_back(§ionTracker); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; m_reporter->sectionStarting(sectionInfo); assertions = m_totals.assertions; return true; } bool RunContext::testForMissingAssertions(Counts& assertions) { if (assertions.total() != 0) return false; if (!m_config->warnAboutMissingAssertions()) return false; if (m_trackerContext.currentTracker().hasChildren()) return false; m_totals.assertions.failed++; assertions.failed++; return true; } void RunContext::sectionEnded(SectionEndInfo const & endInfo) { Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions(assertions); if (!m_activeSections.empty()) { m_activeSections.back()->close(); m_activeSections.pop_back(); } m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); m_messages.clear(); } void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { if (m_unfinishedSections.empty()) m_activeSections.back()->fail(); else m_activeSections.back()->close(); m_activeSections.pop_back(); m_unfinishedSections.push_back(endInfo); } void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { m_reporter->benchmarkStarting( info ); } void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { m_reporter->benchmarkEnded( stats ); } void RunContext::pushScopedMessage(MessageInfo const & message) { m_messages.push_back(message); } void RunContext::popScopedMessage(MessageInfo const & message) { m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); } std::string RunContext::getCurrentTestName() const { return m_activeTestCase ? m_activeTestCase->getTestCaseInfo().name : std::string(); } const AssertionResult * RunContext::getLastResult() const { return &(*m_lastResult); } void RunContext::exceptionEarlyReported() { m_shouldReportUnexpected = false; } void RunContext::handleFatalErrorCondition( StringRef message ) { // First notify reporter that bad things happened m_reporter->fatalErrorEncountered(message); // Don't rebuild the result -- the stringification itself can cause more fatal errors // Instead, fake a result data. AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); tempResult.message = message; AssertionResult result(m_lastAssertionInfo, tempResult); assertionEnded(result); handleUnfinishedSections(); // Recreate section for test case (as we will lose the one that was in scope) auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); Counts assertions; assertions.failed = 1; SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); m_reporter->sectionEnded(testCaseSectionStats); auto const& testInfo = m_activeTestCase->getTestCaseInfo(); Totals deltaTotals; deltaTotals.testCases.failed = 1; deltaTotals.assertions.failed = 1; m_reporter->testCaseEnded(TestCaseStats(testInfo, deltaTotals, std::string(), std::string(), false)); m_totals.testCases.failed++; testGroupEnded(std::string(), m_totals, 1, 1); m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); } bool RunContext::lastAssertionPassed() { return m_lastAssertionPassed; } void RunContext::assertionPassed() { m_lastAssertionPassed = true; ++m_totals.assertions.passed; resetAssertionInfo(); } bool RunContext::aborting() const { return m_totals.assertions.failed == static_cast(m_config->abortAfter()); } void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); m_reporter->sectionStarting(testCaseSection); Counts prevAssertions = m_totals.assertions; double duration = 0; m_shouldReportUnexpected = true; m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; seedRng(*m_config); Timer timer; try { if (m_reporter->getPreferences().shouldRedirectStdOut) { #if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) RedirectedStdOut redirectedStdOut; RedirectedStdErr redirectedStdErr; timer.start(); invokeActiveTestCase(); redirectedCout += redirectedStdOut.str(); redirectedCerr += redirectedStdErr.str(); #else OutputRedirect r(redirectedCout, redirectedCerr); timer.start(); invokeActiveTestCase(); #endif } else { timer.start(); invokeActiveTestCase(); } duration = timer.getElapsedSeconds(); } catch (TestFailureException&) { // This just means the test was aborted due to failure } catch (...) { // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // are reported without translation at the point of origin. if( m_shouldReportUnexpected ) { AssertionReaction dummyReaction; handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); } } Counts assertions = m_totals.assertions - prevAssertions; bool missingAssertions = testForMissingAssertions(assertions); m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); m_reporter->sectionEnded(testCaseSectionStats); } void RunContext::invokeActiveTestCase() { FatalConditionHandler fatalConditionHandler; // Handle signals m_activeTestCase->invoke(); fatalConditionHandler.reset(); } void RunContext::handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. for (auto it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it) sectionEnded(*it); m_unfinishedSections.clear(); } void RunContext::handleExpr( AssertionInfo const& info, ITransientExpression const& expr, AssertionReaction& reaction ) { m_reporter->assertionStarting( info ); bool negated = isFalseTest( info.resultDisposition ); bool result = expr.getResult() != negated; if( result ) { if (!m_includeSuccessfulResults) { assertionPassed(); } else { reportExpr(info, ResultWas::Ok, &expr, negated); } } else { reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); populateReaction( reaction ); } } void RunContext::reportExpr( AssertionInfo const &info, ResultWas::OfType resultType, ITransientExpression const *expr, bool negated ) { m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( negated ) ); AssertionResult assertionResult{ info, data }; assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; assertionEnded( assertionResult ); } void RunContext::handleMessage( AssertionInfo const& info, ResultWas::OfType resultType, StringRef const& message, AssertionReaction& reaction ) { m_reporter->assertionStarting( info ); m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( false ) ); data.message = message; AssertionResult assertionResult{ m_lastAssertionInfo, data }; assertionEnded( assertionResult ); if( !assertionResult.isOk() ) populateReaction( reaction ); } void RunContext::handleUnexpectedExceptionNotThrown( AssertionInfo const& info, AssertionReaction& reaction ) { handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); } void RunContext::handleUnexpectedInflightException( AssertionInfo const& info, std::string const& message, AssertionReaction& reaction ) { m_lastAssertionInfo = info; AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); data.message = message; AssertionResult assertionResult{ info, data }; assertionEnded( assertionResult ); populateReaction( reaction ); } void RunContext::populateReaction( AssertionReaction& reaction ) { reaction.shouldDebugBreak = m_config->shouldDebugBreak(); reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); } void RunContext::handleIncomplete( AssertionInfo const& info ) { m_lastAssertionInfo = info; AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; AssertionResult assertionResult{ info, data }; assertionEnded( assertionResult ); } void RunContext::handleNonExpr( AssertionInfo const &info, ResultWas::OfType resultType, AssertionReaction &reaction ) { m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( false ) ); AssertionResult assertionResult{ info, data }; assertionEnded( assertionResult ); if( !assertionResult.isOk() ) populateReaction( reaction ); } IResultCapture& getResultCapture() { if (auto* capture = getCurrentContext().getResultCapture()) return *capture; else CATCH_INTERNAL_ERROR("No result capture instance"); } } // end catch_run_context.cpp // start catch_section.cpp namespace Catch { Section::Section( SectionInfo const& info ) : m_info( info ), m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) { m_timer.start(); } Section::~Section() { if( m_sectionIncluded ) { SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); if( uncaught_exceptions() ) getResultCapture().sectionEndedEarly( endInfo ); else getResultCapture().sectionEnded( endInfo ); } } // This indicates whether the section should be executed or not Section::operator bool() const { return m_sectionIncluded; } } // end namespace Catch // end catch_section.cpp // start catch_section_info.cpp namespace Catch { SectionInfo::SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, std::string const& _description ) : name( _name ), description( _description ), lineInfo( _lineInfo ) {} SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) {} } // end namespace Catch // end catch_section_info.cpp // start catch_session.cpp // start catch_session.h #include namespace Catch { class Session : NonCopyable { public: Session(); ~Session() override; void showHelp() const; void libIdentify(); int applyCommandLine( int argc, char const * const * argv ); void useConfigData( ConfigData const& configData ); int run( int argc, char* argv[] ); #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) int run( int argc, wchar_t* const argv[] ); #endif int run(); clara::Parser const& cli() const; void cli( clara::Parser const& newParser ); ConfigData& configData(); Config& config(); private: int runInternal(); clara::Parser m_cli; ConfigData m_configData; std::shared_ptr m_config; bool m_startupExceptions = false; }; } // end namespace Catch // end catch_session.h // start catch_version.h #include namespace Catch { // Versioning information struct Version { Version( Version const& ) = delete; Version& operator=( Version const& ) = delete; Version( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, char const * const _branchName, unsigned int _buildNumber ); unsigned int const majorVersion; unsigned int const minorVersion; unsigned int const patchNumber; // buildNumber is only used if branchName is not null char const * const branchName; unsigned int const buildNumber; friend std::ostream& operator << ( std::ostream& os, Version const& version ); }; Version const& libraryVersion(); } // end catch_version.h #include #include namespace Catch { namespace { const int MaxExitCode = 255; IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); return reporter; } IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { return createReporter(config->getReporterName(), config); } auto multi = std::unique_ptr(new ListeningReporter); auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); for (auto const& listener : listeners) { multi->addListener(listener->create(Catch::ReporterConfig(config))); } multi->addReporter(createReporter(config->getReporterName(), config)); return std::move(multi); } Catch::Totals runTests(std::shared_ptr const& config) { // FixMe: Add listeners in order first, then add reporters. auto reporter = makeReporter(config); RunContext context(config, std::move(reporter)); Totals totals; context.testGroupStarting(config->name(), 1, 1); TestSpec testSpec = config->testSpec(); auto const& allTestCases = getAllTestCasesSorted(*config); for (auto const& testCase : allTestCases) { if (!context.aborting() && matchTest(testCase, testSpec, *config)) totals += context.runTest(testCase); else context.reporter().skipTest(testCase); } if (config->warnAboutNoTests() && totals.testCases.total() == 0) { ReusableStringStream testConfig; bool first = true; for (const auto& input : config->getTestsOrTags()) { if (!first) { testConfig << ' '; } first = false; testConfig << input; } context.reporter().noMatchingTestCases(testConfig.str()); totals.error = -1; } context.testGroupEnded(config->name(), totals, 1, 1); return totals; } void applyFilenamesAsTags(Catch::IConfig const& config) { auto& tests = const_cast&>(getAllTestCasesSorted(config)); for (auto& testCase : tests) { auto tags = testCase.tags; std::string filename = testCase.lineInfo.file; auto lastSlash = filename.find_last_of("\\/"); if (lastSlash != std::string::npos) { filename.erase(0, lastSlash); filename[0] = '#'; } auto lastDot = filename.find_last_of('.'); if (lastDot != std::string::npos) { filename.erase(lastDot); } tags.push_back(std::move(filename)); setTags(testCase, tags); } } } // anon namespace Session::Session() { static bool alreadyInstantiated = false; if( alreadyInstantiated ) { try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } catch(...) { getMutableRegistryHub().registerStartupException(); } } const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); if ( !exceptions.empty() ) { m_startupExceptions = true; Colour colourGuard( Colour::Red ); Catch::cerr() << "Errors occurred during startup!" << '\n'; // iterate over all exceptions and notify user for ( const auto& ex_ptr : exceptions ) { try { std::rethrow_exception(ex_ptr); } catch ( std::exception const& ex ) { Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; } } } alreadyInstantiated = true; m_cli = makeCommandLineParser( m_configData ); } Session::~Session() { Catch::cleanUp(); } void Session::showHelp() const { Catch::cout() << "\nCatch v" << libraryVersion() << "\n" << m_cli << std::endl << "For more detailed usage please see the project docs\n" << std::endl; } void Session::libIdentify() { Catch::cout() << std::left << std::setw(16) << "description: " << "A Catch test executable\n" << std::left << std::setw(16) << "category: " << "testframework\n" << std::left << std::setw(16) << "framework: " << "Catch Test\n" << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; } int Session::applyCommandLine( int argc, char const * const * argv ) { if( m_startupExceptions ) return 1; auto result = m_cli.parse( clara::Args( argc, argv ) ); if( !result ) { Catch::cerr() << Colour( Colour::Red ) << "\nError(s) in input:\n" << Column( result.errorMessage() ).indent( 2 ) << "\n\n"; Catch::cerr() << "Run with -? for usage\n" << std::endl; return MaxExitCode; } if( m_configData.showHelp ) showHelp(); if( m_configData.libIdentify ) libIdentify(); m_config.reset(); return 0; } void Session::useConfigData( ConfigData const& configData ) { m_configData = configData; m_config.reset(); } int Session::run( int argc, char* argv[] ) { if( m_startupExceptions ) return 1; int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) returnCode = run(); return returnCode; } #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) int Session::run( int argc, wchar_t* const argv[] ) { char **utf8Argv = new char *[ argc ]; for ( int i = 0; i < argc; ++i ) { int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); utf8Argv[ i ] = new char[ bufSize ]; WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); } int returnCode = run( argc, utf8Argv ); for ( int i = 0; i < argc; ++i ) delete [] utf8Argv[ i ]; delete [] utf8Argv; return returnCode; } #endif int Session::run() { if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { Catch::cout() << "...waiting for enter/ return before starting" << std::endl; static_cast(std::getchar()); } int exitCode = runInternal(); if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; static_cast(std::getchar()); } return exitCode; } clara::Parser const& Session::cli() const { return m_cli; } void Session::cli( clara::Parser const& newParser ) { m_cli = newParser; } ConfigData& Session::configData() { return m_configData; } Config& Session::config() { if( !m_config ) m_config = std::make_shared( m_configData ); return *m_config; } int Session::runInternal() { if( m_startupExceptions ) return 1; if( m_configData.showHelp || m_configData.libIdentify ) return 0; try { config(); // Force config to be constructed seedRng( *m_config ); if( m_configData.filenamesAsTags ) applyFilenamesAsTags( *m_config ); // Handle list request if( Option listed = list( config() ) ) return static_cast( *listed ); auto totals = runTests( m_config ); // Note that on unices only the lower 8 bits are usually used, clamping // the return value to 255 prevents false negative when some multiple // of 256 tests has failed return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast(totals.assertions.failed))); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; return MaxExitCode; } } } // end namespace Catch // end catch_session.cpp // start catch_startup_exception_registry.cpp namespace Catch { void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { try { m_exceptions.push_back(exception); } catch(...) { // If we run out of memory during start-up there's really not a lot more we can do about it std::terminate(); } } std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { return m_exceptions; } } // end namespace Catch // end catch_startup_exception_registry.cpp // start catch_stream.cpp #include #include #include #include #include #include #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wexit-time-destructors" #endif namespace Catch { Catch::IStream::~IStream() = default; namespace detail { namespace { template class StreamBufImpl : public std::streambuf { char data[bufferSize]; WriterF m_writer; public: StreamBufImpl() { setp( data, data + sizeof(data) ); } ~StreamBufImpl() noexcept { StreamBufImpl::sync(); } private: int overflow( int c ) override { sync(); if( c != EOF ) { if( pbase() == epptr() ) m_writer( std::string( 1, static_cast( c ) ) ); else sputc( static_cast( c ) ); } return 0; } int sync() override { if( pbase() != pptr() ) { m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); setp( pbase(), epptr() ); } return 0; } }; /////////////////////////////////////////////////////////////////////////// struct OutputDebugWriter { void operator()( std::string const&str ) { writeToDebugConsole( str ); } }; /////////////////////////////////////////////////////////////////////////// class FileStream : public IStream { mutable std::ofstream m_ofs; public: FileStream( StringRef filename ) { m_ofs.open( filename.c_str() ); CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); } ~FileStream() override = default; public: // IStream std::ostream& stream() const override { return m_ofs; } }; /////////////////////////////////////////////////////////////////////////// class CoutStream : public IStream { mutable std::ostream m_os; public: // Store the streambuf from cout up-front because // cout may get redirected when running tests CoutStream() : m_os( Catch::cout().rdbuf() ) {} ~CoutStream() override = default; public: // IStream std::ostream& stream() const override { return m_os; } }; /////////////////////////////////////////////////////////////////////////// class DebugOutStream : public IStream { std::unique_ptr> m_streamBuf; mutable std::ostream m_os; public: DebugOutStream() : m_streamBuf( new StreamBufImpl() ), m_os( m_streamBuf.get() ) {} ~DebugOutStream() override = default; public: // IStream std::ostream& stream() const override { return m_os; } }; }} // namespace anon::detail /////////////////////////////////////////////////////////////////////////// auto makeStream( StringRef const &filename ) -> IStream const* { if( filename.empty() ) return new detail::CoutStream(); else if( filename[0] == '%' ) { if( filename == "%debug" ) return new detail::DebugOutStream(); else CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); } else return new detail::FileStream( filename ); } // This class encapsulates the idea of a pool of ostringstreams that can be reused. struct StringStreams { std::vector> m_streams; std::vector m_unused; std::ostringstream m_referenceStream; // Used for copy state/ flags from static StringStreams* s_instance; auto add() -> std::size_t { if( m_unused.empty() ) { m_streams.push_back( std::unique_ptr( new std::ostringstream ) ); return m_streams.size()-1; } else { auto index = m_unused.back(); m_unused.pop_back(); return index; } } void release( std::size_t index ) { m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state m_unused.push_back(index); } // !TBD: put in TLS static auto instance() -> StringStreams& { if( !s_instance ) s_instance = new StringStreams(); return *s_instance; } static void cleanup() { delete s_instance; s_instance = nullptr; } }; StringStreams* StringStreams::s_instance = nullptr; void ReusableStringStream::cleanup() { StringStreams::cleanup(); } ReusableStringStream::ReusableStringStream() : m_index( StringStreams::instance().add() ), m_oss( StringStreams::instance().m_streams[m_index].get() ) {} ReusableStringStream::~ReusableStringStream() { static_cast( m_oss )->str(""); m_oss->clear(); StringStreams::instance().release( m_index ); } auto ReusableStringStream::str() const -> std::string { return static_cast( m_oss )->str(); } /////////////////////////////////////////////////////////////////////////// #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions std::ostream& cout() { return std::cout; } std::ostream& cerr() { return std::cerr; } std::ostream& clog() { return std::clog; } #endif } #if defined(__clang__) # pragma clang diagnostic pop #endif // end catch_stream.cpp // start catch_string_manip.cpp #include #include #include #include namespace Catch { bool startsWith( std::string const& s, std::string const& prefix ) { return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); } bool startsWith( std::string const& s, char prefix ) { return !s.empty() && s[0] == prefix; } bool endsWith( std::string const& s, std::string const& suffix ) { return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); } bool endsWith( std::string const& s, char suffix ) { return !s.empty() && s[s.size()-1] == suffix; } bool contains( std::string const& s, std::string const& infix ) { return s.find( infix ) != std::string::npos; } char toLowerCh(char c) { return static_cast( std::tolower( c ) ); } void toLowerInPlace( std::string& s ) { std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); } std::string toLower( std::string const& s ) { std::string lc = s; toLowerInPlace( lc ); return lc; } std::string trim( std::string const& str ) { static char const* whitespaceChars = "\n\r\t "; std::string::size_type start = str.find_first_not_of( whitespaceChars ); std::string::size_type end = str.find_last_not_of( whitespaceChars ); return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); } bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { bool replaced = false; std::size_t i = str.find( replaceThis ); while( i != std::string::npos ) { replaced = true; str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); if( i < str.size()-withThis.size() ) i = str.find( replaceThis, i+withThis.size() ); else i = std::string::npos; } return replaced; } pluralise::pluralise( std::size_t count, std::string const& label ) : m_count( count ), m_label( label ) {} std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { os << pluraliser.m_count << ' ' << pluraliser.m_label; if( pluraliser.m_count != 1 ) os << 's'; return os; } } // end catch_string_manip.cpp // start catch_stringref.cpp #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wexit-time-destructors" #endif #include #include #include namespace { const uint32_t byte_2_lead = 0xC0; const uint32_t byte_3_lead = 0xE0; const uint32_t byte_4_lead = 0xF0; } namespace Catch { StringRef::StringRef( char const* rawChars ) noexcept : StringRef( rawChars, static_cast(std::strlen(rawChars) ) ) {} StringRef::operator std::string() const { return std::string( m_start, m_size ); } void StringRef::swap( StringRef& other ) noexcept { std::swap( m_start, other.m_start ); std::swap( m_size, other.m_size ); std::swap( m_data, other.m_data ); } auto StringRef::c_str() const -> char const* { if( isSubstring() ) const_cast( this )->takeOwnership(); return m_start; } auto StringRef::currentData() const noexcept -> char const* { return m_start; } auto StringRef::isOwned() const noexcept -> bool { return m_data != nullptr; } auto StringRef::isSubstring() const noexcept -> bool { return m_start[m_size] != '\0'; } void StringRef::takeOwnership() { if( !isOwned() ) { m_data = new char[m_size+1]; memcpy( m_data, m_start, m_size ); m_data[m_size] = '\0'; m_start = m_data; } } auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { if( start < m_size ) return StringRef( m_start+start, size ); else return StringRef(); } auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { return size() == other.size() && (std::strncmp( m_start, other.m_start, size() ) == 0); } auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { return !operator==( other ); } auto StringRef::operator[](size_type index) const noexcept -> char { return m_start[index]; } auto StringRef::numberOfCharacters() const noexcept -> size_type { size_type noChars = m_size; // Make adjustments for uft encodings for( size_type i=0; i < m_size; ++i ) { char c = m_start[i]; if( ( c & byte_2_lead ) == byte_2_lead ) { noChars--; if (( c & byte_3_lead ) == byte_3_lead ) noChars--; if( ( c & byte_4_lead ) == byte_4_lead ) noChars--; } } return noChars; } auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { std::string str; str.reserve( lhs.size() + rhs.size() ); str += lhs; str += rhs; return str; } auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { return std::string( lhs ) + std::string( rhs ); } auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { return std::string( lhs ) + std::string( rhs ); } auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { return os.write(str.currentData(), str.size()); } auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { lhs.append(rhs.currentData(), rhs.size()); return lhs; } } // namespace Catch #if defined(__clang__) # pragma clang diagnostic pop #endif // end catch_stringref.cpp // start catch_tag_alias.cpp namespace Catch { TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} } // end catch_tag_alias.cpp // start catch_tag_alias_autoregistrar.cpp namespace Catch { RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { try { getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); } catch (...) { // Do not throw when constructing global objects, instead register the exception to be processed later getMutableRegistryHub().registerStartupException(); } } } // end catch_tag_alias_autoregistrar.cpp // start catch_tag_alias_registry.cpp #include namespace Catch { TagAliasRegistry::~TagAliasRegistry() {} TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { auto it = m_registry.find( alias ); if( it != m_registry.end() ) return &(it->second); else return nullptr; } std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { std::string expandedTestSpec = unexpandedTestSpec; for( auto const& registryKvp : m_registry ) { std::size_t pos = expandedTestSpec.find( registryKvp.first ); if( pos != std::string::npos ) { expandedTestSpec = expandedTestSpec.substr( 0, pos ) + registryKvp.second.tag + expandedTestSpec.substr( pos + registryKvp.first.size() ); } } return expandedTestSpec; } void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, "error: tag alias, '" << alias << "' already registered.\n" << "\tFirst seen at: " << find(alias)->lineInfo << "\n" << "\tRedefined at: " << lineInfo ); } ITagAliasRegistry::~ITagAliasRegistry() {} ITagAliasRegistry const& ITagAliasRegistry::get() { return getRegistryHub().getTagAliasRegistry(); } } // end namespace Catch // end catch_tag_alias_registry.cpp // start catch_test_case_info.cpp #include #include #include #include namespace Catch { TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { if( startsWith( tag, '.' ) || tag == "!hide" ) return TestCaseInfo::IsHidden; else if( tag == "!throws" ) return TestCaseInfo::Throws; else if( tag == "!shouldfail" ) return TestCaseInfo::ShouldFail; else if( tag == "!mayfail" ) return TestCaseInfo::MayFail; else if( tag == "!nonportable" ) return TestCaseInfo::NonPortable; else if( tag == "!benchmark" ) return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); else return TestCaseInfo::None; } bool isReservedTag( std::string const& tag ) { return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast(tag[0]) ); } void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { CATCH_ENFORCE( !isReservedTag(tag), "Tag name: [" << tag << "] is not allowed.\n" << "Tag names starting with non alpha-numeric characters are reserved\n" << _lineInfo ); } TestCase makeTestCase( ITestInvoker* _testCase, std::string const& _className, NameAndTags const& nameAndTags, SourceLineInfo const& _lineInfo ) { bool isHidden = false; // Parse out tags std::vector tags; std::string desc, tag; bool inTag = false; std::string _descOrTags = nameAndTags.tags; for (char c : _descOrTags) { if( !inTag ) { if( c == '[' ) inTag = true; else desc += c; } else { if( c == ']' ) { TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); if( ( prop & TestCaseInfo::IsHidden ) != 0 ) isHidden = true; else if( prop == TestCaseInfo::None ) enforceNotReservedTag( tag, _lineInfo ); tags.push_back( tag ); tag.clear(); inTag = false; } else tag += c; } } if( isHidden ) { tags.push_back( "." ); } TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); return TestCase( _testCase, std::move(info) ); } void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { std::sort(begin(tags), end(tags)); tags.erase(std::unique(begin(tags), end(tags)), end(tags)); testCaseInfo.lcaseTags.clear(); for( auto const& tag : tags ) { std::string lcaseTag = toLower( tag ); testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); testCaseInfo.lcaseTags.push_back( lcaseTag ); } testCaseInfo.tags = std::move(tags); } TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, std::vector const& _tags, SourceLineInfo const& _lineInfo ) : name( _name ), className( _className ), description( _description ), lineInfo( _lineInfo ), properties( None ) { setTags( *this, _tags ); } bool TestCaseInfo::isHidden() const { return ( properties & IsHidden ) != 0; } bool TestCaseInfo::throws() const { return ( properties & Throws ) != 0; } bool TestCaseInfo::okToFail() const { return ( properties & (ShouldFail | MayFail ) ) != 0; } bool TestCaseInfo::expectedToFail() const { return ( properties & (ShouldFail ) ) != 0; } std::string TestCaseInfo::tagsAsString() const { std::string ret; // '[' and ']' per tag std::size_t full_size = 2 * tags.size(); for (const auto& tag : tags) { full_size += tag.size(); } ret.reserve(full_size); for (const auto& tag : tags) { ret.push_back('['); ret.append(tag); ret.push_back(']'); } return ret; } TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} TestCase TestCase::withName( std::string const& _newName ) const { TestCase other( *this ); other.name = _newName; return other; } void TestCase::invoke() const { test->invoke(); } bool TestCase::operator == ( TestCase const& other ) const { return test.get() == other.test.get() && name == other.name && className == other.className; } bool TestCase::operator < ( TestCase const& other ) const { return name < other.name; } TestCaseInfo const& TestCase::getTestCaseInfo() const { return *this; } } // end namespace Catch // end catch_test_case_info.cpp // start catch_test_case_registry_impl.cpp #include namespace Catch { std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { std::vector sorted = unsortedTestCases; switch( config.runOrder() ) { case RunTests::InLexicographicalOrder: std::sort( sorted.begin(), sorted.end() ); break; case RunTests::InRandomOrder: seedRng( config ); RandomNumberGenerator::shuffle( sorted ); break; case RunTests::InDeclarationOrder: // already in declaration order break; } return sorted; } bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); } void enforceNoDuplicateTestCases( std::vector const& functions ) { std::set seenFunctions; for( auto const& function : functions ) { auto prev = seenFunctions.insert( function ); CATCH_ENFORCE( prev.second, "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); } } std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { std::vector filtered; filtered.reserve( testCases.size() ); for( auto const& testCase : testCases ) if( matchTest( testCase, testSpec, config ) ) filtered.push_back( testCase ); return filtered; } std::vector const& getAllTestCasesSorted( IConfig const& config ) { return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); } void TestRegistry::registerTest( TestCase const& testCase ) { std::string name = testCase.getTestCaseInfo().name; if( name.empty() ) { ReusableStringStream rss; rss << "Anonymous test case " << ++m_unnamedCount; return registerTest( testCase.withName( rss.str() ) ); } m_functions.push_back( testCase ); } std::vector const& TestRegistry::getAllTests() const { return m_functions; } std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { if( m_sortedFunctions.empty() ) enforceNoDuplicateTestCases( m_functions ); if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { m_sortedFunctions = sortTests( config, m_functions ); m_currentSortOrder = config.runOrder(); } return m_sortedFunctions; } /////////////////////////////////////////////////////////////////////////// TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} void TestInvokerAsFunction::invoke() const { m_testAsFunction(); } std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { std::string className = classOrQualifiedMethodName; if( startsWith( className, '&' ) ) { std::size_t lastColons = className.rfind( "::" ); std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); if( penultimateColons == std::string::npos ) penultimateColons = 1; className = className.substr( penultimateColons, lastColons-penultimateColons ); } return className; } } // end namespace Catch // end catch_test_case_registry_impl.cpp // start catch_test_case_tracker.cpp #include #include #include #include #include #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wexit-time-destructors" #endif namespace Catch { namespace TestCaseTracking { NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) : name( _name ), location( _location ) {} ITracker::~ITracker() = default; TrackerContext& TrackerContext::instance() { static TrackerContext s_instance; return s_instance; } ITracker& TrackerContext::startRun() { m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); m_currentTracker = nullptr; m_runState = Executing; return *m_rootTracker; } void TrackerContext::endRun() { m_rootTracker.reset(); m_currentTracker = nullptr; m_runState = NotStarted; } void TrackerContext::startCycle() { m_currentTracker = m_rootTracker.get(); m_runState = Executing; } void TrackerContext::completeCycle() { m_runState = CompletedCycle; } bool TrackerContext::completedCycle() const { return m_runState == CompletedCycle; } ITracker& TrackerContext::currentTracker() { return *m_currentTracker; } void TrackerContext::setCurrentTracker( ITracker* tracker ) { m_currentTracker = tracker; } TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const { return tracker->nameAndLocation().name == m_nameAndLocation.name && tracker->nameAndLocation().location == m_nameAndLocation.location; } TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) : m_nameAndLocation( nameAndLocation ), m_ctx( ctx ), m_parent( parent ) {} NameAndLocation const& TrackerBase::nameAndLocation() const { return m_nameAndLocation; } bool TrackerBase::isComplete() const { return m_runState == CompletedSuccessfully || m_runState == Failed; } bool TrackerBase::isSuccessfullyCompleted() const { return m_runState == CompletedSuccessfully; } bool TrackerBase::isOpen() const { return m_runState != NotStarted && !isComplete(); } bool TrackerBase::hasChildren() const { return !m_children.empty(); } void TrackerBase::addChild( ITrackerPtr const& child ) { m_children.push_back( child ); } ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); return( it != m_children.end() ) ? *it : nullptr; } ITracker& TrackerBase::parent() { assert( m_parent ); // Should always be non-null except for root return *m_parent; } void TrackerBase::openChild() { if( m_runState != ExecutingChildren ) { m_runState = ExecutingChildren; if( m_parent ) m_parent->openChild(); } } bool TrackerBase::isSectionTracker() const { return false; } bool TrackerBase::isIndexTracker() const { return false; } void TrackerBase::open() { m_runState = Executing; moveToThis(); if( m_parent ) m_parent->openChild(); } void TrackerBase::close() { // Close any still open children (e.g. generators) while( &m_ctx.currentTracker() != this ) m_ctx.currentTracker().close(); switch( m_runState ) { case NeedsAnotherRun: break; case Executing: m_runState = CompletedSuccessfully; break; case ExecutingChildren: if( m_children.empty() || m_children.back()->isComplete() ) m_runState = CompletedSuccessfully; break; case NotStarted: case CompletedSuccessfully: case Failed: CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); default: CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); } moveToParent(); m_ctx.completeCycle(); } void TrackerBase::fail() { m_runState = Failed; if( m_parent ) m_parent->markAsNeedingAnotherRun(); moveToParent(); m_ctx.completeCycle(); } void TrackerBase::markAsNeedingAnotherRun() { m_runState = NeedsAnotherRun; } void TrackerBase::moveToParent() { assert( m_parent ); m_ctx.setCurrentTracker( m_parent ); } void TrackerBase::moveToThis() { m_ctx.setCurrentTracker( this ); } SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) : TrackerBase( nameAndLocation, ctx, parent ) { if( parent ) { while( !parent->isSectionTracker() ) parent = &parent->parent(); SectionTracker& parentSection = static_cast( *parent ); addNextFilters( parentSection.m_filters ); } } bool SectionTracker::isSectionTracker() const { return true; } SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { std::shared_ptr section; ITracker& currentTracker = ctx.currentTracker(); if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isSectionTracker() ); section = std::static_pointer_cast( childTracker ); } else { section = std::make_shared( nameAndLocation, ctx, ¤tTracker ); currentTracker.addChild( section ); } if( !ctx.completedCycle() ) section->tryOpen(); return *section; } void SectionTracker::tryOpen() { if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) open(); } void SectionTracker::addInitialFilters( std::vector const& filters ) { if( !filters.empty() ) { m_filters.push_back(""); // Root - should never be consulted m_filters.push_back(""); // Test Case - not a section filter m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); } } void SectionTracker::addNextFilters( std::vector const& filters ) { if( filters.size() > 1 ) m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); } IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) : TrackerBase( nameAndLocation, ctx, parent ), m_size( size ) {} bool IndexTracker::isIndexTracker() const { return true; } IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { std::shared_ptr tracker; ITracker& currentTracker = ctx.currentTracker(); if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isIndexTracker() ); tracker = std::static_pointer_cast( childTracker ); } else { tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker, size ); currentTracker.addChild( tracker ); } if( !ctx.completedCycle() && !tracker->isComplete() ) { if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) tracker->moveNext(); tracker->open(); } return *tracker; } int IndexTracker::index() const { return m_index; } void IndexTracker::moveNext() { m_index++; m_children.clear(); } void IndexTracker::close() { TrackerBase::close(); if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) m_runState = Executing; } } // namespace TestCaseTracking using TestCaseTracking::ITracker; using TestCaseTracking::TrackerContext; using TestCaseTracking::SectionTracker; using TestCaseTracking::IndexTracker; } // namespace Catch #if defined(__clang__) # pragma clang diagnostic pop #endif // end catch_test_case_tracker.cpp // start catch_test_registry.cpp namespace Catch { auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); } NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { try { getMutableRegistryHub() .registerTest( makeTestCase( invoker, extractClassName( classOrMethod ), nameAndTags, lineInfo)); } catch (...) { // Do not throw when constructing global objects, instead register the exception to be processed later getMutableRegistryHub().registerStartupException(); } } AutoReg::~AutoReg() = default; } // end catch_test_registry.cpp // start catch_test_spec.cpp #include #include #include #include namespace Catch { TestSpec::Pattern::~Pattern() = default; TestSpec::NamePattern::~NamePattern() = default; TestSpec::TagPattern::~TagPattern() = default; TestSpec::ExcludedPattern::~ExcludedPattern() = default; TestSpec::NamePattern::NamePattern( std::string const& name ) : m_wildcardPattern( toLower( name ), CaseSensitive::No ) {} bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { return m_wildcardPattern.matches( toLower( testCase.name ) ); } TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { return std::find(begin(testCase.lcaseTags), end(testCase.lcaseTags), m_tag) != end(testCase.lcaseTags); } TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { // All patterns in a filter must match for the filter to be a match for( auto const& pattern : m_patterns ) { if( !pattern->matches( testCase ) ) return false; } return true; } bool TestSpec::hasFilters() const { return !m_filters.empty(); } bool TestSpec::matches( TestCaseInfo const& testCase ) const { // A TestSpec matches if any filter matches for( auto const& filter : m_filters ) if( filter.matches( testCase ) ) return true; return false; } } // end catch_test_spec.cpp // start catch_test_spec_parser.cpp namespace Catch { TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} TestSpecParser& TestSpecParser::parse( std::string const& arg ) { m_mode = None; m_exclusion = false; m_start = std::string::npos; m_arg = m_tagAliases->expandAliases( arg ); m_escapeChars.clear(); for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) visitChar( m_arg[m_pos] ); if( m_mode == Name ) addPattern(); return *this; } TestSpec TestSpecParser::testSpec() { addFilter(); return m_testSpec; } void TestSpecParser::visitChar( char c ) { if( m_mode == None ) { switch( c ) { case ' ': return; case '~': m_exclusion = true; return; case '[': return startNewMode( Tag, ++m_pos ); case '"': return startNewMode( QuotedName, ++m_pos ); case '\\': return escape(); default: startNewMode( Name, m_pos ); break; } } if( m_mode == Name ) { if( c == ',' ) { addPattern(); addFilter(); } else if( c == '[' ) { if( subString() == "exclude:" ) m_exclusion = true; else addPattern(); startNewMode( Tag, ++m_pos ); } else if( c == '\\' ) escape(); } else if( m_mode == EscapedName ) m_mode = Name; else if( m_mode == QuotedName && c == '"' ) addPattern(); else if( m_mode == Tag && c == ']' ) addPattern(); } void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { m_mode = mode; m_start = start; } void TestSpecParser::escape() { if( m_mode == None ) m_start = m_pos; m_mode = EscapedName; m_escapeChars.push_back( m_pos ); } std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } void TestSpecParser::addFilter() { if( !m_currentFilter.m_patterns.empty() ) { m_testSpec.m_filters.push_back( m_currentFilter ); m_currentFilter = TestSpec::Filter(); } } TestSpec parseTestSpec( std::string const& arg ) { return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); } } // namespace Catch // end catch_test_spec_parser.cpp // start catch_timer.cpp #include static const uint64_t nanosecondsInSecond = 1000000000; namespace Catch { auto getCurrentNanosecondsSinceEpoch() -> uint64_t { return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); } auto estimateClockResolution() -> uint64_t { uint64_t sum = 0; static const uint64_t iterations = 1000000; auto startTime = getCurrentNanosecondsSinceEpoch(); for( std::size_t i = 0; i < iterations; ++i ) { uint64_t ticks; uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); do { ticks = getCurrentNanosecondsSinceEpoch(); } while( ticks == baseTicks ); auto delta = ticks - baseTicks; sum += delta; // If we have been calibrating for over 3 seconds -- the clock // is terrible and we should move on. // TBD: How to signal that the measured resolution is probably wrong? if (ticks > startTime + 3 * nanosecondsInSecond) { return sum / i; } } // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers // - and potentially do more iterations if there's a high variance. return sum/iterations; } auto getEstimatedClockResolution() -> uint64_t { static auto s_resolution = estimateClockResolution(); return s_resolution; } void Timer::start() { m_nanoseconds = getCurrentNanosecondsSinceEpoch(); } auto Timer::getElapsedNanoseconds() const -> uint64_t { return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; } auto Timer::getElapsedMicroseconds() const -> uint64_t { return getElapsedNanoseconds()/1000; } auto Timer::getElapsedMilliseconds() const -> unsigned int { return static_cast(getElapsedMicroseconds()/1000); } auto Timer::getElapsedSeconds() const -> double { return getElapsedMicroseconds()/1000000.0; } } // namespace Catch // end catch_timer.cpp // start catch_tostring.cpp #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wexit-time-destructors" # pragma clang diagnostic ignored "-Wglobal-constructors" #endif // Enable specific decls locally #if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) #define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER #endif #include #include namespace Catch { namespace Detail { const std::string unprintableString = "{?}"; namespace { const int hexThreshold = 255; struct Endianness { enum Arch { Big, Little }; static Arch which() { union _{ int asInt; char asChar[sizeof (int)]; } u; u.asInt = 1; return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; } }; } std::string rawMemoryToString( const void *object, std::size_t size ) { // Reverse order for little endian architectures int i = 0, end = static_cast( size ), inc = 1; if( Endianness::which() == Endianness::Little ) { i = end-1; end = inc = -1; } unsigned char const *bytes = static_cast(object); ReusableStringStream rss; rss << "0x" << std::setfill('0') << std::hex; for( ; i != end; i += inc ) rss << std::setw(2) << static_cast(bytes[i]); return rss.str(); } } template std::string fpToString( T value, int precision ) { if (std::isnan(value)) { return "nan"; } ReusableStringStream rss; rss << std::setprecision( precision ) << std::fixed << value; std::string d = rss.str(); std::size_t i = d.find_last_not_of( '0' ); if( i != std::string::npos && i != d.size()-1 ) { if( d[i] == '.' ) i++; d = d.substr( 0, i+1 ); } return d; } //// ======================================================= //// // // Out-of-line defs for full specialization of StringMaker // //// ======================================================= //// std::string StringMaker::convert(const std::string& str) { if (!getCurrentContext().getConfig()->showInvisibles()) { return '"' + str + '"'; } std::string s("\""); for (char c : str) { switch (c) { case '\n': s.append("\\n"); break; case '\t': s.append("\\t"); break; default: s.push_back(c); break; } } s.append("\""); return s; } #ifdef CATCH_CONFIG_WCHAR std::string StringMaker::convert(const std::wstring& wstr) { std::string s; s.reserve(wstr.size()); for (auto c : wstr) { s += (c <= 0xff) ? static_cast(c) : '?'; } return ::Catch::Detail::stringify(s); } #endif std::string StringMaker::convert(char const* str) { if (str) { return ::Catch::Detail::stringify(std::string{ str }); } else { return{ "{null string}" }; } } std::string StringMaker::convert(char* str) { if (str) { return ::Catch::Detail::stringify(std::string{ str }); } else { return{ "{null string}" }; } } #ifdef CATCH_CONFIG_WCHAR std::string StringMaker::convert(wchar_t const * str) { if (str) { return ::Catch::Detail::stringify(std::wstring{ str }); } else { return{ "{null string}" }; } } std::string StringMaker::convert(wchar_t * str) { if (str) { return ::Catch::Detail::stringify(std::wstring{ str }); } else { return{ "{null string}" }; } } #endif std::string StringMaker::convert(int value) { return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(long value) { return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(long long value) { ReusableStringStream rss; rss << value; if (value > Detail::hexThreshold) { rss << " (0x" << std::hex << value << ')'; } return rss.str(); } std::string StringMaker::convert(unsigned int value) { return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(unsigned long value) { return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(unsigned long long value) { ReusableStringStream rss; rss << value; if (value > Detail::hexThreshold) { rss << " (0x" << std::hex << value << ')'; } return rss.str(); } std::string StringMaker::convert(bool b) { return b ? "true" : "false"; } std::string StringMaker::convert(char value) { if (value == '\r') { return "'\\r'"; } else if (value == '\f') { return "'\\f'"; } else if (value == '\n') { return "'\\n'"; } else if (value == '\t') { return "'\\t'"; } else if ('\0' <= value && value < ' ') { return ::Catch::Detail::stringify(static_cast(value)); } else { char chstr[] = "' '"; chstr[1] = value; return chstr; } } std::string StringMaker::convert(signed char c) { return ::Catch::Detail::stringify(static_cast(c)); } std::string StringMaker::convert(unsigned char c) { return ::Catch::Detail::stringify(static_cast(c)); } std::string StringMaker::convert(std::nullptr_t) { return "nullptr"; } std::string StringMaker::convert(float value) { return fpToString(value, 5) + 'f'; } std::string StringMaker::convert(double value) { return fpToString(value, 10); } std::string ratio_string::symbol() { return "a"; } std::string ratio_string::symbol() { return "f"; } std::string ratio_string::symbol() { return "p"; } std::string ratio_string::symbol() { return "n"; } std::string ratio_string::symbol() { return "u"; } std::string ratio_string::symbol() { return "m"; } } // end namespace Catch #if defined(__clang__) # pragma clang diagnostic pop #endif // end catch_tostring.cpp // start catch_totals.cpp namespace Catch { Counts Counts::operator - ( Counts const& other ) const { Counts diff; diff.passed = passed - other.passed; diff.failed = failed - other.failed; diff.failedButOk = failedButOk - other.failedButOk; return diff; } Counts& Counts::operator += ( Counts const& other ) { passed += other.passed; failed += other.failed; failedButOk += other.failedButOk; return *this; } std::size_t Counts::total() const { return passed + failed + failedButOk; } bool Counts::allPassed() const { return failed == 0 && failedButOk == 0; } bool Counts::allOk() const { return failed == 0; } Totals Totals::operator - ( Totals const& other ) const { Totals diff; diff.assertions = assertions - other.assertions; diff.testCases = testCases - other.testCases; return diff; } Totals& Totals::operator += ( Totals const& other ) { assertions += other.assertions; testCases += other.testCases; return *this; } Totals Totals::delta( Totals const& prevTotals ) const { Totals diff = *this - prevTotals; if( diff.assertions.failed > 0 ) ++diff.testCases.failed; else if( diff.assertions.failedButOk > 0 ) ++diff.testCases.failedButOk; else ++diff.testCases.passed; return diff; } } // end catch_totals.cpp // start catch_uncaught_exceptions.cpp #include namespace Catch { bool uncaught_exceptions() { #if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) return std::uncaught_exceptions() > 0; #else return std::uncaught_exception(); #endif } } // end namespace Catch // end catch_uncaught_exceptions.cpp // start catch_version.cpp #include namespace Catch { Version::Version ( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, char const * const _branchName, unsigned int _buildNumber ) : majorVersion( _majorVersion ), minorVersion( _minorVersion ), patchNumber( _patchNumber ), branchName( _branchName ), buildNumber( _buildNumber ) {} std::ostream& operator << ( std::ostream& os, Version const& version ) { os << version.majorVersion << '.' << version.minorVersion << '.' << version.patchNumber; // branchName is never null -> 0th char is \0 if it is empty if (version.branchName[0]) { os << '-' << version.branchName << '.' << version.buildNumber; } return os; } Version const& libraryVersion() { static Version version( 2, 2, 3, "", 0 ); return version; } } // end catch_version.cpp // start catch_wildcard_pattern.cpp #include namespace Catch { WildcardPattern::WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) : m_caseSensitivity( caseSensitivity ), m_pattern( adjustCase( pattern ) ) { if( startsWith( m_pattern, '*' ) ) { m_pattern = m_pattern.substr( 1 ); m_wildcard = WildcardAtStart; } if( endsWith( m_pattern, '*' ) ) { m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); } } bool WildcardPattern::matches( std::string const& str ) const { switch( m_wildcard ) { case NoWildcard: return m_pattern == adjustCase( str ); case WildcardAtStart: return endsWith( adjustCase( str ), m_pattern ); case WildcardAtEnd: return startsWith( adjustCase( str ), m_pattern ); case WildcardAtBothEnds: return contains( adjustCase( str ), m_pattern ); default: CATCH_INTERNAL_ERROR( "Unknown enum" ); } } std::string WildcardPattern::adjustCase( std::string const& str ) const { return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; } } // end catch_wildcard_pattern.cpp // start catch_xmlwriter.cpp #include using uchar = unsigned char; namespace Catch { namespace { size_t trailingBytes(unsigned char c) { if ((c & 0xE0) == 0xC0) { return 2; } if ((c & 0xF0) == 0xE0) { return 3; } if ((c & 0xF8) == 0xF0) { return 4; } CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); } uint32_t headerValue(unsigned char c) { if ((c & 0xE0) == 0xC0) { return c & 0x1F; } if ((c & 0xF0) == 0xE0) { return c & 0x0F; } if ((c & 0xF8) == 0xF0) { return c & 0x07; } CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); } void hexEscapeChar(std::ostream& os, unsigned char c) { os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast(c); } } // anonymous namespace XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) : m_str( str ), m_forWhat( forWhat ) {} void XmlEncode::encodeTo( std::ostream& os ) const { // Apostrophe escaping not necessary if we always use " to write attributes // (see: http://www.w3.org/TR/xml/#syntax) for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { uchar c = m_str[idx]; switch (c) { case '<': os << "<"; break; case '&': os << "&"; break; case '>': // See: http://www.w3.org/TR/xml/#syntax if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') os << ">"; else os << c; break; case '\"': if (m_forWhat == ForAttributes) os << """; else os << c; break; default: // Check for control characters and invalid utf-8 // Escape control characters in standard ascii // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { hexEscapeChar(os, c); break; } // Plain ASCII: Write it to stream if (c < 0x7F) { os << c; break; } // UTF-8 territory // Check if the encoding is valid and if it is not, hex escape bytes. // Important: We do not check the exact decoded values for validity, only the encoding format // First check that this bytes is a valid lead byte: // This means that it is not encoded as 1111 1XXX // Or as 10XX XXXX if (c < 0xC0 || c >= 0xF8) { hexEscapeChar(os, c); break; } auto encBytes = trailingBytes(c); // Are there enough bytes left to avoid accessing out-of-bounds memory? if (idx + encBytes - 1 >= m_str.size()) { hexEscapeChar(os, c); break; } // The header is valid, check data // The next encBytes bytes must together be a valid utf-8 // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) bool valid = true; uint32_t value = headerValue(c); for (std::size_t n = 1; n < encBytes; ++n) { uchar nc = m_str[idx + n]; valid &= ((nc & 0xC0) == 0x80); value = (value << 6) | (nc & 0x3F); } if ( // Wrong bit pattern of following bytes (!valid) || // Overlong encodings (value < 0x80) || (0x80 <= value && value < 0x800 && encBytes > 2) || (0x800 < value && value < 0x10000 && encBytes > 3) || // Encoded value out of range (value >= 0x110000) ) { hexEscapeChar(os, c); break; } // If we got here, this is in fact a valid(ish) utf-8 sequence for (std::size_t n = 0; n < encBytes; ++n) { os << m_str[idx + n]; } idx += encBytes - 1; break; } } } std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { xmlEncode.encodeTo( os ); return os; } XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) : m_writer( writer ) {} XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept : m_writer( other.m_writer ){ other.m_writer = nullptr; } XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { if ( m_writer ) { m_writer->endElement(); } m_writer = other.m_writer; other.m_writer = nullptr; return *this; } XmlWriter::ScopedElement::~ScopedElement() { if( m_writer ) m_writer->endElement(); } XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { m_writer->writeText( text, indent ); return *this; } XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) { writeDeclaration(); } XmlWriter::~XmlWriter() { while( !m_tags.empty() ) endElement(); } XmlWriter& XmlWriter::startElement( std::string const& name ) { ensureTagClosed(); newlineIfNecessary(); m_os << m_indent << '<' << name; m_tags.push_back( name ); m_indent += " "; m_tagIsOpen = true; return *this; } XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { ScopedElement scoped( this ); startElement( name ); return scoped; } XmlWriter& XmlWriter::endElement() { newlineIfNecessary(); m_indent = m_indent.substr( 0, m_indent.size()-2 ); if( m_tagIsOpen ) { m_os << "/>"; m_tagIsOpen = false; } else { m_os << m_indent << ""; } m_os << std::endl; m_tags.pop_back(); return *this; } XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { if( !name.empty() && !attribute.empty() ) m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; return *this; } XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; return *this; } XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { if( !text.empty() ){ bool tagWasOpen = m_tagIsOpen; ensureTagClosed(); if( tagWasOpen && indent ) m_os << m_indent; m_os << XmlEncode( text ); m_needsNewline = true; } return *this; } XmlWriter& XmlWriter::writeComment( std::string const& text ) { ensureTagClosed(); m_os << m_indent << ""; m_needsNewline = true; return *this; } void XmlWriter::writeStylesheetRef( std::string const& url ) { m_os << "\n"; } XmlWriter& XmlWriter::writeBlankLine() { ensureTagClosed(); m_os << '\n'; return *this; } void XmlWriter::ensureTagClosed() { if( m_tagIsOpen ) { m_os << ">" << std::endl; m_tagIsOpen = false; } } void XmlWriter::writeDeclaration() { m_os << "\n"; } void XmlWriter::newlineIfNecessary() { if( m_needsNewline ) { m_os << std::endl; m_needsNewline = false; } } } // end catch_xmlwriter.cpp // start catch_reporter_bases.cpp #include #include #include #include #include namespace Catch { void prepareExpandedExpression(AssertionResult& result) { result.getExpandedExpression(); } // Because formatting using c++ streams is stateful, drop down to C is required // Alternatively we could use stringstream, but its performance is... not good. std::string getFormattedDuration( double duration ) { // Max exponent + 1 is required to represent the whole part // + 1 for decimal point // + 3 for the 3 decimal places // + 1 for null terminator const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; char buffer[maxDoubleSize]; // Save previous errno, to prevent sprintf from overwriting it ErrnoGuard guard; #ifdef _MSC_VER sprintf_s(buffer, "%.3f", duration); #else sprintf(buffer, "%.3f", duration); #endif return std::string(buffer); } TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) :StreamingReporterBase(_config) {} void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} bool TestEventListenerBase::assertionEnded(AssertionStats const &) { return false; } } // end namespace Catch // end catch_reporter_bases.cpp // start catch_reporter_compact.cpp namespace { #ifdef CATCH_PLATFORM_MAC const char* failedString() { return "FAILED"; } const char* passedString() { return "PASSED"; } #else const char* failedString() { return "failed"; } const char* passedString() { return "passed"; } #endif // Colour::LightGrey Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } std::string bothOrAll( std::size_t count ) { return count == 1 ? std::string() : count == 2 ? "both " : "all " ; } } // anon namespace namespace Catch { namespace { // Colour, message variants: // - white: No tests ran. // - red: Failed [both/all] N test cases, failed [both/all] M assertions. // - white: Passed [both/all] N test cases (no assertions). // - red: Failed N tests cases, failed M assertions. // - green: Passed [both/all] N tests cases with M assertions. void printTotals(std::ostream& out, const Totals& totals) { if (totals.testCases.total() == 0) { out << "No tests ran."; } else if (totals.testCases.failed == totals.testCases.total()) { Colour colour(Colour::ResultError); const std::string qualify_assertions_failed = totals.assertions.failed == totals.assertions.total() ? bothOrAll(totals.assertions.failed) : std::string(); out << "Failed " << bothOrAll(totals.testCases.failed) << pluralise(totals.testCases.failed, "test case") << ", " "failed " << qualify_assertions_failed << pluralise(totals.assertions.failed, "assertion") << '.'; } else if (totals.assertions.total() == 0) { out << "Passed " << bothOrAll(totals.testCases.total()) << pluralise(totals.testCases.total(), "test case") << " (no assertions)."; } else if (totals.assertions.failed) { Colour colour(Colour::ResultError); out << "Failed " << pluralise(totals.testCases.failed, "test case") << ", " "failed " << pluralise(totals.assertions.failed, "assertion") << '.'; } else { Colour colour(Colour::ResultSuccess); out << "Passed " << bothOrAll(totals.testCases.passed) << pluralise(totals.testCases.passed, "test case") << " with " << pluralise(totals.assertions.passed, "assertion") << '.'; } } // Implementation of CompactReporter formatting class AssertionPrinter { public: AssertionPrinter& operator= (AssertionPrinter const&) = delete; AssertionPrinter(AssertionPrinter const&) = delete; AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) : stream(_stream) , result(_stats.assertionResult) , messages(_stats.infoMessages) , itMessage(_stats.infoMessages.begin()) , printInfoMessages(_printInfoMessages) {} void print() { printSourceInfo(); itMessage = messages.begin(); switch (result.getResultType()) { case ResultWas::Ok: printResultType(Colour::ResultSuccess, passedString()); printOriginalExpression(); printReconstructedExpression(); if (!result.hasExpression()) printRemainingMessages(Colour::None); else printRemainingMessages(); break; case ResultWas::ExpressionFailed: if (result.isOk()) printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); else printResultType(Colour::Error, failedString()); printOriginalExpression(); printReconstructedExpression(); printRemainingMessages(); break; case ResultWas::ThrewException: printResultType(Colour::Error, failedString()); printIssue("unexpected exception with message:"); printMessage(); printExpressionWas(); printRemainingMessages(); break; case ResultWas::FatalErrorCondition: printResultType(Colour::Error, failedString()); printIssue("fatal error condition with message:"); printMessage(); printExpressionWas(); printRemainingMessages(); break; case ResultWas::DidntThrowException: printResultType(Colour::Error, failedString()); printIssue("expected exception, got none"); printExpressionWas(); printRemainingMessages(); break; case ResultWas::Info: printResultType(Colour::None, "info"); printMessage(); printRemainingMessages(); break; case ResultWas::Warning: printResultType(Colour::None, "warning"); printMessage(); printRemainingMessages(); break; case ResultWas::ExplicitFailure: printResultType(Colour::Error, failedString()); printIssue("explicitly"); printRemainingMessages(Colour::None); break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: printResultType(Colour::Error, "** internal error **"); break; } } private: void printSourceInfo() const { Colour colourGuard(Colour::FileName); stream << result.getSourceInfo() << ':'; } void printResultType(Colour::Code colour, std::string const& passOrFail) const { if (!passOrFail.empty()) { { Colour colourGuard(colour); stream << ' ' << passOrFail; } stream << ':'; } } void printIssue(std::string const& issue) const { stream << ' ' << issue; } void printExpressionWas() { if (result.hasExpression()) { stream << ';'; { Colour colour(dimColour()); stream << " expression was:"; } printOriginalExpression(); } } void printOriginalExpression() const { if (result.hasExpression()) { stream << ' ' << result.getExpression(); } } void printReconstructedExpression() const { if (result.hasExpandedExpression()) { { Colour colour(dimColour()); stream << " for: "; } stream << result.getExpandedExpression(); } } void printMessage() { if (itMessage != messages.end()) { stream << " '" << itMessage->message << '\''; ++itMessage; } } void printRemainingMessages(Colour::Code colour = dimColour()) { if (itMessage == messages.end()) return; // using messages.end() directly yields (or auto) compilation error: std::vector::const_iterator itEnd = messages.end(); const std::size_t N = static_cast(std::distance(itMessage, itEnd)); { Colour colourGuard(colour); stream << " with " << pluralise(N, "message") << ':'; } for (; itMessage != itEnd; ) { // If this assertion is a warning ignore any INFO messages if (printInfoMessages || itMessage->type != ResultWas::Info) { stream << " '" << itMessage->message << '\''; if (++itMessage != itEnd) { Colour colourGuard(dimColour()); stream << " and"; } } } } private: std::ostream& stream; AssertionResult const& result; std::vector messages; std::vector::const_iterator itMessage; bool printInfoMessages; }; } // anon namespace std::string CompactReporter::getDescription() { return "Reports test results on a single line, suitable for IDEs"; } ReporterPreferences CompactReporter::getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = false; return prefs; } void CompactReporter::noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << '\'' << std::endl; } void CompactReporter::assertionStarting( AssertionInfo const& ) {} bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; // Drop out if result was successful and we're not printing those if( !m_config->includeSuccessfulResults() && result.isOk() ) { if( result.getResultType() != ResultWas::Warning ) return false; printInfoMessages = false; } AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); printer.print(); stream << std::endl; return true; } void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { if (m_config->showDurations() == ShowDurations::Always) { stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { printTotals( stream, _testRunStats.totals ); stream << '\n' << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } CompactReporter::~CompactReporter() {} CATCH_REGISTER_REPORTER( "compact", CompactReporter ) } // end namespace Catch // end catch_reporter_compact.cpp // start catch_reporter_console.cpp #include #include #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch // Note that 4062 (not all labels are handled // and default is missing) is enabled #endif namespace Catch { namespace { // Formatter impl for ConsoleReporter class ConsoleAssertionPrinter { public: ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) : stream(_stream), stats(_stats), result(_stats.assertionResult), colour(Colour::None), message(result.getMessage()), messages(_stats.infoMessages), printInfoMessages(_printInfoMessages) { switch (result.getResultType()) { case ResultWas::Ok: colour = Colour::Success; passOrFail = "PASSED"; //if( result.hasMessage() ) if (_stats.infoMessages.size() == 1) messageLabel = "with message"; if (_stats.infoMessages.size() > 1) messageLabel = "with messages"; break; case ResultWas::ExpressionFailed: if (result.isOk()) { colour = Colour::Success; passOrFail = "FAILED - but was ok"; } else { colour = Colour::Error; passOrFail = "FAILED"; } if (_stats.infoMessages.size() == 1) messageLabel = "with message"; if (_stats.infoMessages.size() > 1) messageLabel = "with messages"; break; case ResultWas::ThrewException: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "due to unexpected exception with "; if (_stats.infoMessages.size() == 1) messageLabel += "message"; if (_stats.infoMessages.size() > 1) messageLabel += "messages"; break; case ResultWas::FatalErrorCondition: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "due to a fatal error condition"; break; case ResultWas::DidntThrowException: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "because no exception was thrown where one was expected"; break; case ResultWas::Info: messageLabel = "info"; break; case ResultWas::Warning: messageLabel = "warning"; break; case ResultWas::ExplicitFailure: passOrFail = "FAILED"; colour = Colour::Error; if (_stats.infoMessages.size() == 1) messageLabel = "explicitly with message"; if (_stats.infoMessages.size() > 1) messageLabel = "explicitly with messages"; break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: passOrFail = "** internal error **"; colour = Colour::Error; break; } } void print() const { printSourceInfo(); if (stats.totals.assertions.total() > 0) { if (result.isOk()) stream << '\n'; printResultType(); printOriginalExpression(); printReconstructedExpression(); } else { stream << '\n'; } printMessage(); } private: void printResultType() const { if (!passOrFail.empty()) { Colour colourGuard(colour); stream << passOrFail << ":\n"; } } void printOriginalExpression() const { if (result.hasExpression()) { Colour colourGuard(Colour::OriginalExpression); stream << " "; stream << result.getExpressionInMacro(); stream << '\n'; } } void printReconstructedExpression() const { if (result.hasExpandedExpression()) { stream << "with expansion:\n"; Colour colourGuard(Colour::ReconstructedExpression); stream << Column(result.getExpandedExpression()).indent(2) << '\n'; } } void printMessage() const { if (!messageLabel.empty()) stream << messageLabel << ':' << '\n'; for (auto const& msg : messages) { // If this assertion is a warning ignore any INFO messages if (printInfoMessages || msg.type != ResultWas::Info) stream << Column(msg.message).indent(2) << '\n'; } } void printSourceInfo() const { Colour colourGuard(Colour::FileName); stream << result.getSourceInfo() << ": "; } std::ostream& stream; AssertionStats const& stats; AssertionResult const& result; Colour::Code colour; std::string passOrFail; std::string messageLabel; std::string message; std::vector messages; bool printInfoMessages; }; std::size_t makeRatio(std::size_t number, std::size_t total) { std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; return (ratio == 0 && number > 0) ? 1 : ratio; } std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { if (i > j && i > k) return i; else if (j > k) return j; else return k; } struct ColumnInfo { enum Justification { Left, Right }; std::string name; int width; Justification justification; }; struct ColumnBreak {}; struct RowBreak {}; class Duration { enum class Unit { Auto, Nanoseconds, Microseconds, Milliseconds, Seconds, Minutes }; static const uint64_t s_nanosecondsInAMicrosecond = 1000; static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; uint64_t m_inNanoseconds; Unit m_units; public: explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) : m_inNanoseconds(inNanoseconds), m_units(units) { if (m_units == Unit::Auto) { if (m_inNanoseconds < s_nanosecondsInAMicrosecond) m_units = Unit::Nanoseconds; else if (m_inNanoseconds < s_nanosecondsInAMillisecond) m_units = Unit::Microseconds; else if (m_inNanoseconds < s_nanosecondsInASecond) m_units = Unit::Milliseconds; else if (m_inNanoseconds < s_nanosecondsInAMinute) m_units = Unit::Seconds; else m_units = Unit::Minutes; } } auto value() const -> double { switch (m_units) { case Unit::Microseconds: return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); case Unit::Milliseconds: return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); case Unit::Seconds: return m_inNanoseconds / static_cast(s_nanosecondsInASecond); case Unit::Minutes: return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); default: return static_cast(m_inNanoseconds); } } auto unitsAsString() const -> std::string { switch (m_units) { case Unit::Nanoseconds: return "ns"; case Unit::Microseconds: return "µs"; case Unit::Milliseconds: return "ms"; case Unit::Seconds: return "s"; case Unit::Minutes: return "m"; default: return "** internal error **"; } } friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { return os << duration.value() << " " << duration.unitsAsString(); } }; } // end anon namespace class TablePrinter { std::ostream& m_os; std::vector m_columnInfos; std::ostringstream m_oss; int m_currentColumn = -1; bool m_isOpen = false; public: TablePrinter( std::ostream& os, std::vector columnInfos ) : m_os( os ), m_columnInfos( std::move( columnInfos ) ) {} auto columnInfos() const -> std::vector const& { return m_columnInfos; } void open() { if (!m_isOpen) { m_isOpen = true; *this << RowBreak(); for (auto const& info : m_columnInfos) *this << info.name << ColumnBreak(); *this << RowBreak(); m_os << Catch::getLineOfChars<'-'>() << "\n"; } } void close() { if (m_isOpen) { *this << RowBreak(); m_os << std::endl; m_isOpen = false; } } template friend TablePrinter& operator << (TablePrinter& tp, T const& value) { tp.m_oss << value; return tp; } friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { auto colStr = tp.m_oss.str(); // This takes account of utf8 encodings auto strSize = Catch::StringRef(colStr).numberOfCharacters(); tp.m_oss.str(""); tp.open(); if (tp.m_currentColumn == static_cast(tp.m_columnInfos.size() - 1)) { tp.m_currentColumn = -1; tp.m_os << "\n"; } tp.m_currentColumn++; auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; auto padding = (strSize + 2 < static_cast(colInfo.width)) ? std::string(colInfo.width - (strSize + 2), ' ') : std::string(); if (colInfo.justification == ColumnInfo::Left) tp.m_os << colStr << padding << " "; else tp.m_os << padding << colStr << " "; return tp; } friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { if (tp.m_currentColumn > 0) { tp.m_os << "\n"; tp.m_currentColumn = -1; } return tp; } }; ConsoleReporter::ConsoleReporter(ReporterConfig const& config) : StreamingReporterBase(config), m_tablePrinter(new TablePrinter(config.stream(), { { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, { "iters", 8, ColumnInfo::Right }, { "elapsed ns", 14, ColumnInfo::Right }, { "average", 14, ColumnInfo::Right } })) {} ConsoleReporter::~ConsoleReporter() = default; std::string ConsoleReporter::getDescription() { return "Reports test results as plain lines of text"; } void ConsoleReporter::noMatchingTestCases(std::string const& spec) { stream << "No test cases matched '" << spec << '\'' << std::endl; } void ConsoleReporter::assertionStarting(AssertionInfo const&) {} bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { AssertionResult const& result = _assertionStats.assertionResult; bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); // Drop out if result was successful but we're not printing them. if (!includeResults && result.getResultType() != ResultWas::Warning) return false; lazyPrint(); ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); printer.print(); stream << std::endl; return true; } void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { m_headerPrinted = false; StreamingReporterBase::sectionStarting(_sectionInfo); } void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { m_tablePrinter->close(); if (_sectionStats.missingAssertions) { lazyPrint(); Colour colour(Colour::ResultError); if (m_sectionStack.size() > 1) stream << "\nNo assertions in section"; else stream << "\nNo assertions in test case"; stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } if (m_config->showDurations() == ShowDurations::Always) { stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; } if (m_headerPrinted) { m_headerPrinted = false; } StreamingReporterBase::sectionEnded(_sectionStats); } void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { lazyPrintWithoutClosingBenchmarkTable(); auto nameCol = Column( info.name ).width( static_cast( m_tablePrinter->columnInfos()[0].width - 2 ) ); bool firstLine = true; for (auto line : nameCol) { if (!firstLine) (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); else firstLine = false; (*m_tablePrinter) << line << ColumnBreak(); } } void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); (*m_tablePrinter) << stats.iterations << ColumnBreak() << stats.elapsedTimeInNanoseconds << ColumnBreak() << average << ColumnBreak(); } void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { m_tablePrinter->close(); StreamingReporterBase::testCaseEnded(_testCaseStats); m_headerPrinted = false; } void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { if (currentGroupInfo.used) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; printTotals(_testGroupStats.totals); stream << '\n' << std::endl; } StreamingReporterBase::testGroupEnded(_testGroupStats); } void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { printTotalsDivider(_testRunStats.totals); printTotals(_testRunStats.totals); stream << std::endl; StreamingReporterBase::testRunEnded(_testRunStats); } void ConsoleReporter::lazyPrint() { m_tablePrinter->close(); lazyPrintWithoutClosingBenchmarkTable(); } void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { if (!currentTestRunInfo.used) lazyPrintRunInfo(); if (!currentGroupInfo.used) lazyPrintGroupInfo(); if (!m_headerPrinted) { printTestCaseAndSectionHeader(); m_headerPrinted = true; } } void ConsoleReporter::lazyPrintRunInfo() { stream << '\n' << getLineOfChars<'~'>() << '\n'; Colour colour(Colour::SecondaryText); stream << currentTestRunInfo->name << " is a Catch v" << libraryVersion() << " host application.\n" << "Run with -? for options\n\n"; if (m_config->rngSeed() != 0) stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; currentTestRunInfo.used = true; } void ConsoleReporter::lazyPrintGroupInfo() { if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { printClosedHeader("Group: " + currentGroupInfo->name); currentGroupInfo.used = true; } } void ConsoleReporter::printTestCaseAndSectionHeader() { assert(!m_sectionStack.empty()); printOpenHeader(currentTestCaseInfo->name); if (m_sectionStack.size() > 1) { Colour colourGuard(Colour::Headers); auto it = m_sectionStack.begin() + 1, // Skip first section (test case) itEnd = m_sectionStack.end(); for (; it != itEnd; ++it) printHeaderString(it->name, 2); } SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; if (!lineInfo.empty()) { stream << getLineOfChars<'-'>() << '\n'; Colour colourGuard(Colour::FileName); stream << lineInfo << '\n'; } stream << getLineOfChars<'.'>() << '\n' << std::endl; } void ConsoleReporter::printClosedHeader(std::string const& _name) { printOpenHeader(_name); stream << getLineOfChars<'.'>() << '\n'; } void ConsoleReporter::printOpenHeader(std::string const& _name) { stream << getLineOfChars<'-'>() << '\n'; { Colour colourGuard(Colour::Headers); printHeaderString(_name); } } // if string has a : in first line will set indent to follow it on // subsequent lines void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { std::size_t i = _string.find(": "); if (i != std::string::npos) i += 2; else i = 0; stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; } struct SummaryColumn { SummaryColumn( std::string _label, Colour::Code _colour ) : label( std::move( _label ) ), colour( _colour ) {} SummaryColumn addRow( std::size_t count ) { ReusableStringStream rss; rss << count; std::string row = rss.str(); for (auto& oldRow : rows) { while (oldRow.size() < row.size()) oldRow = ' ' + oldRow; while (oldRow.size() > row.size()) row = ' ' + row; } rows.push_back(row); return *this; } std::string label; Colour::Code colour; std::vector rows; }; void ConsoleReporter::printTotals( Totals const& totals ) { if (totals.testCases.total() == 0) { stream << Colour(Colour::Warning) << "No tests ran\n"; } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { stream << Colour(Colour::ResultSuccess) << "All tests passed"; stream << " (" << pluralise(totals.assertions.passed, "assertion") << " in " << pluralise(totals.testCases.passed, "test case") << ')' << '\n'; } else { std::vector columns; columns.push_back(SummaryColumn("", Colour::None) .addRow(totals.testCases.total()) .addRow(totals.assertions.total())); columns.push_back(SummaryColumn("passed", Colour::Success) .addRow(totals.testCases.passed) .addRow(totals.assertions.passed)); columns.push_back(SummaryColumn("failed", Colour::ResultError) .addRow(totals.testCases.failed) .addRow(totals.assertions.failed)); columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) .addRow(totals.testCases.failedButOk) .addRow(totals.assertions.failedButOk)); printSummaryRow("test cases", columns, 0); printSummaryRow("assertions", columns, 1); } } void ConsoleReporter::printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row) { for (auto col : cols) { std::string value = col.rows[row]; if (col.label.empty()) { stream << label << ": "; if (value != "0") stream << value; else stream << Colour(Colour::Warning) << "- none -"; } else if (value != "0") { stream << Colour(Colour::LightGrey) << " | "; stream << Colour(col.colour) << value << ' ' << col.label; } } stream << '\n'; } void ConsoleReporter::printTotalsDivider(Totals const& totals) { if (totals.testCases.total() > 0) { std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) findMax(failedRatio, failedButOkRatio, passedRatio)++; while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) findMax(failedRatio, failedButOkRatio, passedRatio)--; stream << Colour(Colour::Error) << std::string(failedRatio, '='); stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); if (totals.testCases.allPassed()) stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); else stream << Colour(Colour::Success) << std::string(passedRatio, '='); } else { stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); } stream << '\n'; } void ConsoleReporter::printSummaryDivider() { stream << getLineOfChars<'-'>() << '\n'; } CATCH_REGISTER_REPORTER("console", ConsoleReporter) } // end namespace Catch #if defined(_MSC_VER) #pragma warning(pop) #endif // end catch_reporter_console.cpp // start catch_reporter_junit.cpp #include #include #include #include namespace Catch { namespace { std::string getCurrentTimestamp() { // Beware, this is not reentrant because of backward compatibility issues // Also, UTC only, again because of backward compatibility (%z is C++11) time_t rawtime; std::time(&rawtime); auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); #ifdef _MSC_VER std::tm timeInfo = {}; gmtime_s(&timeInfo, &rawtime); #else std::tm* timeInfo; timeInfo = std::gmtime(&rawtime); #endif char timeStamp[timeStampSize]; const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; #ifdef _MSC_VER std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); #else std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif return std::string(timeStamp); } std::string fileNameTag(const std::vector &tags) { auto it = std::find_if(begin(tags), end(tags), [] (std::string const& tag) {return tag.front() == '#'; }); if (it != tags.end()) return it->substr(1); return std::string(); } } // anonymous namespace JunitReporter::JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = true; } JunitReporter::~JunitReporter() {} std::string JunitReporter::getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; } void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); } void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { suiteTimer.start(); stdOutForSuite.clear(); stdErrForSuite.clear(); unexpectedExceptions = 0; CumulativeReporterBase::testGroupStarting( groupInfo ); } void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { m_okToFail = testCaseInfo.okToFail(); } bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { stdOutForSuite += testCaseStats.stdOut; stdErrForSuite += testCaseStats.stdErr; CumulativeReporterBase::testCaseEnded( testCaseStats ); } void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { double suiteTime = suiteTimer.getElapsedSeconds(); CumulativeReporterBase::testGroupEnded( testGroupStats ); writeGroup( *m_testGroups.back(), suiteTime ); } void JunitReporter::testRunEndedCumulative() { xml.endElement(); } void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); TestGroupStats const& stats = groupNode.value; xml.writeAttribute( "name", stats.groupInfo.name ); xml.writeAttribute( "errors", unexpectedExceptions ); xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); xml.writeAttribute( "tests", stats.totals.assertions.total() ); xml.writeAttribute( "hostname", "tbd" ); // !TBD if( m_config->showDurations() == ShowDurations::Never ) xml.writeAttribute( "time", "" ); else xml.writeAttribute( "time", suiteTime ); xml.writeAttribute( "timestamp", getCurrentTimestamp() ); // Write test cases for( auto const& child : groupNode.children ) writeTestCase( *child ); xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); } void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { TestCaseStats const& stats = testCaseNode.value; // All test cases have exactly one section - which represents the // test case itself. That section may have 0-n nested sections assert( testCaseNode.children.size() == 1 ); SectionNode const& rootSection = *testCaseNode.children.front(); std::string className = stats.testInfo.className; if( className.empty() ) { className = fileNameTag(stats.testInfo.tags); if ( className.empty() ) className = "global"; } if ( !m_config->name().empty() ) className = m_config->name() + "." + className; writeSection( className, "", rootSection ); } void JunitReporter::writeSection( std::string const& className, std::string const& rootName, SectionNode const& sectionNode ) { std::string name = trim( sectionNode.stats.sectionInfo.name ); if( !rootName.empty() ) name = rootName + '/' + name; if( !sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty() ) { XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); if( className.empty() ) { xml.writeAttribute( "classname", name ); xml.writeAttribute( "name", "root" ); } else { xml.writeAttribute( "classname", className ); xml.writeAttribute( "name", name ); } xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); writeAssertions( sectionNode ); if( !sectionNode.stdOut.empty() ) xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); if( !sectionNode.stdErr.empty() ) xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); } for( auto const& childNode : sectionNode.childSections ) if( className.empty() ) writeSection( name, "", *childNode ); else writeSection( className, name, *childNode ); } void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { for( auto const& assertion : sectionNode.assertions ) writeAssertion( assertion ); } void JunitReporter::writeAssertion( AssertionStats const& stats ) { AssertionResult const& result = stats.assertionResult; if( !result.isOk() ) { std::string elementName; switch( result.getResultType() ) { case ResultWas::ThrewException: case ResultWas::FatalErrorCondition: elementName = "error"; break; case ResultWas::ExplicitFailure: elementName = "failure"; break; case ResultWas::ExpressionFailed: elementName = "failure"; break; case ResultWas::DidntThrowException: elementName = "failure"; break; // We should never see these here: case ResultWas::Info: case ResultWas::Warning: case ResultWas::Ok: case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: elementName = "internalError"; break; } XmlWriter::ScopedElement e = xml.scopedElement( elementName ); xml.writeAttribute( "message", result.getExpandedExpression() ); xml.writeAttribute( "type", result.getTestMacroName() ); ReusableStringStream rss; if( !result.getMessage().empty() ) rss << result.getMessage() << '\n'; for( auto const& msg : stats.infoMessages ) if( msg.type == ResultWas::Info ) rss << msg.message << '\n'; rss << "at " << result.getSourceInfo(); xml.writeText( rss.str(), false ); } } CATCH_REGISTER_REPORTER( "junit", JunitReporter ) } // end namespace Catch // end catch_reporter_junit.cpp // start catch_reporter_listening.cpp #include namespace Catch { void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { m_listeners.push_back( std::move( listener ) ); } void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); m_reporter = std::move( reporter ); } ReporterPreferences ListeningReporter::getPreferences() const { return m_reporter->getPreferences(); } std::set ListeningReporter::getSupportedVerbosities() { return std::set{ }; } void ListeningReporter::noMatchingTestCases( std::string const& spec ) { for ( auto const& listener : m_listeners ) { listener->noMatchingTestCases( spec ); } m_reporter->noMatchingTestCases( spec ); } void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { for ( auto const& listener : m_listeners ) { listener->benchmarkStarting( benchmarkInfo ); } m_reporter->benchmarkStarting( benchmarkInfo ); } void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { for ( auto const& listener : m_listeners ) { listener->benchmarkEnded( benchmarkStats ); } m_reporter->benchmarkEnded( benchmarkStats ); } void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { for ( auto const& listener : m_listeners ) { listener->testRunStarting( testRunInfo ); } m_reporter->testRunStarting( testRunInfo ); } void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { for ( auto const& listener : m_listeners ) { listener->testGroupStarting( groupInfo ); } m_reporter->testGroupStarting( groupInfo ); } void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { for ( auto const& listener : m_listeners ) { listener->testCaseStarting( testInfo ); } m_reporter->testCaseStarting( testInfo ); } void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { for ( auto const& listener : m_listeners ) { listener->sectionStarting( sectionInfo ); } m_reporter->sectionStarting( sectionInfo ); } void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { for ( auto const& listener : m_listeners ) { listener->assertionStarting( assertionInfo ); } m_reporter->assertionStarting( assertionInfo ); } // The return value indicates if the messages buffer should be cleared: bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { for( auto const& listener : m_listeners ) { static_cast( listener->assertionEnded( assertionStats ) ); } return m_reporter->assertionEnded( assertionStats ); } void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { for ( auto const& listener : m_listeners ) { listener->sectionEnded( sectionStats ); } m_reporter->sectionEnded( sectionStats ); } void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { for ( auto const& listener : m_listeners ) { listener->testCaseEnded( testCaseStats ); } m_reporter->testCaseEnded( testCaseStats ); } void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { for ( auto const& listener : m_listeners ) { listener->testGroupEnded( testGroupStats ); } m_reporter->testGroupEnded( testGroupStats ); } void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { for ( auto const& listener : m_listeners ) { listener->testRunEnded( testRunStats ); } m_reporter->testRunEnded( testRunStats ); } void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { for ( auto const& listener : m_listeners ) { listener->skipTest( testInfo ); } m_reporter->skipTest( testInfo ); } bool ListeningReporter::isMulti() const { return true; } } // end namespace Catch // end catch_reporter_listening.cpp // start catch_reporter_xml.cpp #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch // Note that 4062 (not all labels are handled // and default is missing) is enabled #endif namespace Catch { XmlReporter::XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_xml(_config.stream()) { m_reporterPrefs.shouldRedirectStdOut = true; } XmlReporter::~XmlReporter() = default; std::string XmlReporter::getDescription() { return "Reports test results as an XML document"; } std::string XmlReporter::getStylesheetRef() const { return std::string(); } void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { m_xml .writeAttribute( "filename", sourceInfo.file ) .writeAttribute( "line", sourceInfo.line ); } void XmlReporter::noMatchingTestCases( std::string const& s ) { StreamingReporterBase::noMatchingTestCases( s ); } void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { StreamingReporterBase::testRunStarting( testInfo ); std::string stylesheetRef = getStylesheetRef(); if( !stylesheetRef.empty() ) m_xml.writeStylesheetRef( stylesheetRef ); m_xml.startElement( "Catch" ); if( !m_config->name().empty() ) m_xml.writeAttribute( "name", m_config->name() ); } void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) .writeAttribute( "name", groupInfo.name ); } void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ) .writeAttribute( "name", trim( testInfo.name ) ) .writeAttribute( "description", testInfo.description ) .writeAttribute( "tags", testInfo.tagsAsString() ); writeSourceInfo( testInfo.lineInfo ); if ( m_config->showDurations() == ShowDurations::Always ) m_testCaseTimer.start(); m_xml.ensureTagClosed(); } void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) .writeAttribute( "name", trim( sectionInfo.name ) ) .writeAttribute( "description", sectionInfo.description ); writeSourceInfo( sectionInfo.lineInfo ); m_xml.ensureTagClosed(); } } void XmlReporter::assertionStarting( AssertionInfo const& ) { } bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { AssertionResult const& result = assertionStats.assertionResult; bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); if( includeResults || result.getResultType() == ResultWas::Warning ) { // Print any info messages in tags. for( auto const& msg : assertionStats.infoMessages ) { if( msg.type == ResultWas::Info && includeResults ) { m_xml.scopedElement( "Info" ) .writeText( msg.message ); } else if ( msg.type == ResultWas::Warning ) { m_xml.scopedElement( "Warning" ) .writeText( msg.message ); } } } // Drop out if result was successful but we're not printing them. if( !includeResults && result.getResultType() != ResultWas::Warning ) return true; // Print the expression if there is one. if( result.hasExpression() ) { m_xml.startElement( "Expression" ) .writeAttribute( "success", result.succeeded() ) .writeAttribute( "type", result.getTestMacroName() ); writeSourceInfo( result.getSourceInfo() ); m_xml.scopedElement( "Original" ) .writeText( result.getExpression() ); m_xml.scopedElement( "Expanded" ) .writeText( result.getExpandedExpression() ); } // And... Print a result applicable to each result type. switch( result.getResultType() ) { case ResultWas::ThrewException: m_xml.startElement( "Exception" ); writeSourceInfo( result.getSourceInfo() ); m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; case ResultWas::FatalErrorCondition: m_xml.startElement( "FatalErrorCondition" ); writeSourceInfo( result.getSourceInfo() ); m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; case ResultWas::Info: m_xml.scopedElement( "Info" ) .writeText( result.getMessage() ); break; case ResultWas::Warning: // Warning will already have been written break; case ResultWas::ExplicitFailure: m_xml.startElement( "Failure" ); writeSourceInfo( result.getSourceInfo() ); m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; default: break; } if( result.hasExpression() ) m_xml.endElement(); return true; } void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); e.writeAttribute( "successes", sectionStats.assertions.passed ); e.writeAttribute( "failures", sectionStats.assertions.failed ); e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); m_xml.endElement(); } } void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); if( !testCaseStats.stdOut.empty() ) m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); if( !testCaseStats.stdErr.empty() ) m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); m_xml.endElement(); } void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { StreamingReporterBase::testGroupEnded( testGroupStats ); // TODO: Check testGroupStats.aborting and act accordingly. m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); m_xml.endElement(); } void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { StreamingReporterBase::testRunEnded( testRunStats ); m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testRunStats.totals.assertions.passed ) .writeAttribute( "failures", testRunStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); m_xml.endElement(); } CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch #if defined(_MSC_VER) #pragma warning(pop) #endif // end catch_reporter_xml.cpp namespace Catch { LeakDetector leakDetector; } #ifdef __clang__ #pragma clang diagnostic pop #endif // end catch_impl.hpp #endif #ifdef CATCH_CONFIG_MAIN // start catch_default_main.hpp #ifndef __OBJC__ #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) // Standard C/C++ Win32 Unicode wmain entry point extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { #else // Standard C/C++ main entry point int main (int argc, char * argv[]) { #endif return Catch::Session().run( argc, argv ); } #else // __OBJC__ // Objective-C entry point int main (int argc, char * const argv[]) { #if !CATCH_ARC_ENABLED NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; #endif Catch::registerTestMethods(); int result = Catch::Session().run( argc, (char**)argv ); #if !CATCH_ARC_ENABLED [pool drain]; #endif return result; } #endif // __OBJC__ // end catch_default_main.hpp #endif #if !defined(CATCH_CONFIG_IMPL_ONLY) #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif #if !defined(CATCH_CONFIG_DISABLE) ////// // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) #endif// CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() // "BDD-style" convenience wrappers #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc ) #define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc ) #define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) #define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc ) #define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) // "BDD-style" convenience wrappers #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #define GIVEN( desc ) SECTION( std::string(" Given: ") + desc ) #define WHEN( desc ) SECTION( std::string(" When: ") + desc ) #define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc ) #define THEN( desc ) SECTION( std::string(" Then: ") + desc ) #define AND_THEN( desc ) SECTION( std::string(" And: ") + desc ) using Catch::Detail::Approx; #else ////// // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL #define CATCH_REQUIRE( ... ) (void)(0) #define CATCH_REQUIRE_FALSE( ... ) (void)(0) #define CATCH_REQUIRE_THROWS( ... ) (void)(0) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) #endif// CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) #define CATCH_CHECK( ... ) (void)(0) #define CATCH_CHECK_FALSE( ... ) (void)(0) #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) #define CATCH_CHECK_NOFAIL( ... ) (void)(0) #define CATCH_CHECK_THROWS( ... ) (void)(0) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_CHECK_NOTHROW( ... ) (void)(0) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_CHECK_THAT( arg, matcher ) (void)(0) #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_INFO( msg ) (void)(0) #define CATCH_WARN( msg ) (void)(0) #define CATCH_CAPTURE( msg ) (void)(0) #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) #define CATCH_SECTION( ... ) #define CATCH_FAIL( ... ) (void)(0) #define CATCH_FAIL_CHECK( ... ) (void)(0) #define CATCH_SUCCEED( ... ) (void)(0) #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) // "BDD-style" convenience wrappers #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) #define CATCH_GIVEN( desc ) #define CATCH_WHEN( desc ) #define CATCH_AND_WHEN( desc ) #define CATCH_THEN( desc ) #define CATCH_AND_THEN( desc ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else #define REQUIRE( ... ) (void)(0) #define REQUIRE_FALSE( ... ) (void)(0) #define REQUIRE_THROWS( ... ) (void)(0) #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define REQUIRE_NOTHROW( ... ) (void)(0) #define CHECK( ... ) (void)(0) #define CHECK_FALSE( ... ) (void)(0) #define CHECKED_IF( ... ) if (__VA_ARGS__) #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) #define CHECK_NOFAIL( ... ) (void)(0) #define CHECK_THROWS( ... ) (void)(0) #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) #define CHECK_THROWS_WITH( expr, matcher ) (void)(0) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define CHECK_NOTHROW( ... ) (void)(0) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CHECK_THAT( arg, matcher ) (void)(0) #define REQUIRE_THAT( arg, matcher ) (void)(0) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define INFO( msg ) (void)(0) #define WARN( msg ) (void)(0) #define CAPTURE( msg ) (void)(0) #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) #define METHOD_AS_TEST_CASE( method, ... ) #define REGISTER_TEST_CASE( Function, ... ) (void)(0) #define SECTION( ... ) #define FAIL( ... ) (void)(0) #define FAIL_CHECK( ... ) (void)(0) #define SUCCEED( ... ) (void)(0) #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) // "BDD-style" convenience wrappers #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) #define GIVEN( desc ) #define WHEN( desc ) #define AND_WHEN( desc ) #define THEN( desc ) #define AND_THEN( desc ) using Catch::Detail::Approx; #endif #endif // ! CATCH_CONFIG_IMPL_ONLY // start catch_reenable_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(pop) # else # pragma clang diagnostic pop # endif #elif defined __GNUC__ # pragma GCC diagnostic pop #endif // end catch_reenable_warnings.h // end catch.hpp #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED segyio-1.8.3/external/catch2/CMakeLists.txt0000664000372000037200000000074213407674361020170 0ustar travistraviscmake_minimum_required(VERSION 2.8.12) project(catch2 CXX) # Dummy source file added because INTERFACE type # library is not available in CMake 2.8.12 # it's STATIC, because MSVC would otherwise not generate a .lib file, making # "linking" (for header path) fail later # # TODO: when cmake minimum version is bumped to 3.x series, replace with # an INTERFACE library add_library(catch2 STATIC dummy.cpp) target_include_directories(catch2 SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) segyio-1.8.3/man/0000775000372000037200000000000013407674361013212 5ustar travistravissegyio-1.8.3/man/segyio-catr.10000664000372000037200000000345713407674361015533 0ustar travistravis.TH SEGYIO-CATR 1 .SH NAME segyio-catr \- Print selected headers from FILE .SH SYNPOSIS .B segyio-catr [\fIOPTION\fR]... \fIFILE\fR .SH DESCRIPTION .B segyio-cath Print selected traceheaders from SEG-Y file FILE .PP The flag \fB--range\fR takes up to three vales; START, STOP, STEP, which is a closed inteval from START to STOP. The third value STEP can be specified to print i.e. every other trace in the interval. All values are defaulted to 1. Traces are 1-indexed. Flags \fB-r\fR and \fB-t\fR can be called multiple times. .PP Mandatory arguments to long options are mandatory for short options too. .SH OPTIONS .TP .BR \-t ", " \-\-trace=\fINUMBER\fR trace(s) to print .TP .BR \-r ", " \-\-range " " "\fISTART\fR [\fISTOP\fR \fISTEP\fR]" range of trace(s) to print. \fISTOP\fR and \fISTEP\fR are optional, and defaults to \fISTART\fR and 1 respectively. .TP .BR \-f ", " \-\-format=\fIFORMAT\fR override sample format. defaults to inferring from the binary header. available formats: \fIibm ieee short long char\fR .TP .BR \-s ", " \-\-strict fail on unreadable tracefields .TP .BR \-S ", " \-\-non-strict don't fail on unreadable fields this is the default behavior .TP .BR \-n ", " \-\-nonzero only print fields with non-zero values .TP .BR \-d ", " \-\-description print with byte offset and field description .TP .BR \-k ", " \-\-segyio print with segyio tracefield names .TP .BR \-v ", " \-\-verbose increase verbosity .TP .BR \-\-version output version information and exit .TP .BR \-\-help display this help and exit .SH COPYRIGHT Copyright © Statoil ASA. License LGPLv3+: GNU LGPL version 3 or later . .PP This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. .SH SEE ALSO segyio-cath(1), segyio-catb(1) segyio-1.8.3/man/segyio-crop.10000664000372000037200000000401613407674361015535 0ustar travistravis.TH SEGYIO-CROP 1 .SH NAME segyio-crop \- Copy a sub cube from SRC to DST .SH SYNPOSIS .B segyio-crop [\fIOPTION\fR]... \fISOURCE DEST\fR .SH DESCRIPTION .B segyio-crop Copy a sub cube from SEG-Y file SOURCE to DEST. .PP If no \fBbegin\fR or \fBend\fR options are specified, this program is essentially a copy. If a \fBbegin\fR option is omitted, the program copies from the start of the file. If an \fBend\fR option is omitted, the program copies until the end of file is reached. .PP Mandatory arguments to long options are mandatory for short options too. .SH OPTIONS .TP .BR \-i ", " \-\-iline-begin =\fILINE\fR inline to copy from .TP .BR \-I ", " \-\-iline-end=\fILINE\fR inline to copy to (inclusive) .TP .BR \-x ", " \-\-xline-begin =\fILINE\fR crossline to copy from .TP .BR \-X ", " \-\-xline-end=\fILINE\fR crossnline to copy to (inclusive) .TP .BR \-\-inline-begin =\fILINE\fR alias to \-\-iline-begin .TP .BR \-\-inline-end =\fILINE\fR alias to \-\-iline-end .TP .BR \-\-crossline-begin =\fILINE\fR alias to \-\-xline-begin .TP .BR \-\-crossline-end =\fILINE\fR alias to \-\-xline-end .TP .BR \-f ", " \-\-format=\fIFORMAT\fR override sample format. defaults to inferring from the binary header. available formats: \fIibm ieee short long char\fR .TP .BR \-s ", " \-\-sample-begin =\fILINE\fR sample to copy from .TP .BR \-S ", " \-\-sample-end=\fILINE\fR sample to copy to (inclusive) .TP .BR \-b ", " \-\-il =\fINUM\fR inline header word byte offset; must align with SEG-Y defined offsets defaults to 189 .TP .BR \-B ", " \-\-xl =\fINUM\fR crossline header word byte offset; must align with SEG-Y defined offsets defaults to 193 .TP .BR \-v ", " \-\-verbose increase verbosity .TP .BR \-\-version output version information and exit .TP .BR \-\-help display this help and exit .SH COPYRIGHT Copyright © Statoil ASA. License LGPLv3+: GNU LGPL version 3 or later . .PP This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. segyio-1.8.3/man/CMakeLists.txt0000664000372000037200000000034513407674361015754 0ustar travistravisproject(segyio-man) if(NOT UNIX) return() endif() install(FILES segyio-cath.1 segyio-catb.1 segyio-catr.1 segyio-crop.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 ) segyio-1.8.3/man/segyio-catb.10000664000372000037200000000144613407674361015507 0ustar travistravis.TH SEGYIO-CATB 1 .SH NAME segyio-catb \- Concatenate SEG-Y binary header and print on seismic unix format .SH SYNPOSIS .B segyio-catb [\fIOPTION\fR]... [\fIFILE\fR]... .SH DESCRIPTION .B segyio-catb Concatenate the SEG-Y binary header in FILEs. .SH OPTIONS .TP .BR \-n ", " \-\-nonzero only print fields with non-zero values .TP .BR \-d ", " \-\-description print with byte offset and field description .TP .BR \-\-version output version information and exit .TP .BR \-\-help display this help and exit .SH COPYRIGHT Copyright © Statoil ASA. License LGPLv3+: GNU LGPL version 3 or later . .PP This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. .SH SEE ALSO segyio-cath(1), segyio-catb(1) segyio-1.8.3/man/segyio-cath.10000664000372000037200000000215113407674361015507 0ustar travistravis.TH SEGYIO-CATH 1 .SH NAME segyio-cath \- Concatenate SEG-Y text headers and print on the standard output .SH SYNPOSIS .B segyio-cath [\fIOPTION\fR]... [\fIFILE\fR]... .SH DESCRIPTION .B segyio-cath Concatenate the SEG-Y text headers in FILEs. .PP By default, only the non-extended header is printed, which is equivalent to --num 0. .PP Mandatory arguments to long options are mandatory for short options too. .SH OPTIONS .TP .BR \-n ", " \-\-num =\fINUM\fR the textual header to show, starts at 0 .TP .BR \-a ", " \-\-all print all headers .TP .BR \-s ", " \-\-strict abort if a header or file is not found primarily meant for shell scripts .TP .BR \-S ", " \-\-nonstrict ignore missing headers this is the default behaviour .TP .BR \-\-version output version information and exit .TP .BR \-\-help display this help and exit .SH COPYRIGHT Copyright © Statoil ASA. License LGPLv3+: GNU LGPL version 3 or later . .PP This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. .SH SEE ALSO segyio-catb(1), segyio-catr(1) segyio-1.8.3/appveyor.yml0000664000372000037200000000560113407674361015031 0ustar travistravisversion: 1.0.{build} clone_depth: 1 configuration: - Release os: Visual Studio 2015 image: Visual Studio 2015 platform: - x86 - x64 environment: MEX: -DBUILD_MEX=OFF INSTALL_DIR: C:\projects\segyio-install TWINE_PASSWORD: secure: kTga6+rLL1fNpKqFNcX0QZNyqiYaHsEfSS4k6wvUoTE= matrix: - PYTHON: C:\Python27 LANG: -DBUILD_PYTHON=ON PYTHON_VERSION: 27 - PYTHON: C:\Python35 LANG: -DBUILD_PYTHON=ON PYTHON_VERSION: 35 - PYTHON: C:\Python36 LANG: -DBUILD_PYTHON=ON PYTHON_VERSION: 36 - PYTHON: C:\Python37 LANG: -DBUILD_PYTHON=ON PYTHON_VERSION: 37 matrix: fast_finish: true install: - git submodule update --init --recursive - IF DEFINED PYTHON (IF "%platform%" == "x64" SET PYTHON=%PYTHON%-x64) - IF DEFINED PYTHON SET PATH=%PYTHON%;%PYTHON%\Scripts;%PATH% - IF DEFINED PYTHON pip install -r requirements.txt - IF DEFINED PYTHON pip install twine wheel pytest pytest-runner before_build: - IF DEFINED PYTHON SET LANG=%LANG% -DPYTHON_EXECUTABLE=%PYTHON%\python - git fetch --tags # python extensions with setup.py typically requires building with the same # compiler as python itself, but it seems that the extern C does a reasonable # job of keeping it binary compatible. For python < 3.0, copy the shared lib # into the build directory (because otherwise visual c++ 9.0 is invoked, and it # supports no C99. For newer pythons, setup.py is capable of building segyio build_script: - cmake --version - IF "%platform%" == "x64" set W64="-GVisual Studio 14 2015 Win64" - mkdir build - ps: pushd build - cmake %APPVEYOR_BUILD_FOLDER% %W64% %MEX% %LANG% -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% -DBUILD_SHARED_LIBS=ON - cmake --build . --config "%configuration%" --target install - ctest -C "%configuration%" --output-on-failure - ps: popd - ps: pushd build/python - IF DEFINED PYTHON python %APPVEYOR_BUILD_FOLDER%/setup.py bdist_wheel - ps: popd test_script: - set PATH=%INSTALL_DIR%\bin;%PATH% - ps: pushd build/python - IF DEFINED PYTHON FOR /F "tokens=*" %%G IN ('dir /b dist\*.whl') DO pip install dist/%%G - ps: popd - IF DEFINED PYTHON python -c "import segyio;f=segyio.open('test-data/small.sgy');print(f.ilines)" - IF DEFINED PYTHON python python/examples/scan_min_max.py test-data/small.sgy before_deploy: - ps: pushd build/python after_deploy: - ps: popd deploy_script: - ps: | Write-Host "TAG: $env:APPVEYOR_REPO_TAG" If ($env:APPVEYOR_REPO_TAG -eq "false") { return } Write-Host "Uploading wheels to pypi" Invoke-Expression "twine upload -u statoil-travis --skip-existing dist/*" If ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) } segyio-1.8.3/setup.py0000664000372000037200000001070213407674361014151 0ustar travistravis#!/usr/bin/env python import os import sys from setuptools import setup, Extension long_description = """ ======= SEGY IO ======= https://segyio.readthedocs.io Introduction ------------ Segyio is a small LGPL licensed C library for easy interaction with SEG Y formatted seismic data, with language bindings for Python and Matlab. Segyio is an attempt to create an easy-to-use, embeddable, community-oriented library for seismic applications. Features are added as they are needed; suggestions and contributions of all kinds are very welcome. Feature summary --------------- * A low-level C interface with few assumptions; easy to bind to other languages. * Read and write binary and textual headers. * Read and write traces, trace headers. * Easy to use and native-feeling python interface with numpy integration. Project goals ------------- Segyio does necessarily attempt to be the end-all of SEG-Y interactions; rather, we aim to lower the barrier to interacting with SEG-Y files for embedding, new applications or free-standing programs. Additionally, the aim is not to support the full standard or all exotic (but correctly) formatted files out there. Some assumptions are made, such as: * All traces in a file are assumed to be of the same sample size. * It is assumed all lines have the same number of traces. The writing functionality in Segyio is largely meant to *modify* or adapt files. A file created from scratch is not necessarily a to-spec SEG-Y file, as we only necessarily write the header fields segyio needs to make sense of the geometry. It is still highly recommended that SEG-Y files are maintained and written according to specification, but segyio does not mandate this. """ def src(x): root = os.path.dirname( __file__ ) return os.path.abspath(os.path.join(root, x)) if 'win' in sys.platform: extra_libs = [] else: extra_libs = ['m'] def getversion(): # if this is a tarball distribution, the .git-directory won't be avilable # and setuptools_scm will crash hard. good tarballs are built with a # pre-generated version.py, so parse that and extract version from it # # set the SEGYIO_NO_GIT_VER environment variable to ignore a version from # git (useful when building for debian or other distributions) if not 'SEGYIO_NO_GIT_VER' in os.environ and os.path.isdir(src('.git')): return { 'use_scm_version': { 'root': src(''), 'write_to': src('python/segyio/version.py') } } pkgversion = { 'version': '0.0.0' } versionfile = src('python/segyio/version.py') if not os.path.exists(versionfile): return pkgversion import ast with open(versionfile) as f: root = ast.parse(f.read()) for node in ast.walk(root): if not isinstance(node, ast.Assign): continue if len(node.targets) == 1 and node.targets[0].id == 'version': pkgversion['version'] = node.value.s return pkgversion setup(name='segyio', description='Simple & fast IO for SEG-Y files', long_description=long_description, author='Statoil ASA', author_email='fg_gpl@statoil.com', url='https://github.com/Statoil/segyio', package_dir={'' : src('python')}, packages=['segyio', 'segyio.su'], package_data={ 'segyio': ['segyio.dll'], }, license='LGPL-3.0', ext_modules=[Extension('segyio._segyio', sources=[src('python/segyio/segyio.cpp')], include_dirs=[src('lib/include')], libraries=['segyio'] + extra_libs )], platforms='any', install_requires=['numpy >=1.10'], setup_requires=['setuptools >=28', 'setuptools_scm', 'pytest-runner'], tests_require=['pytest'], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Other Environment', 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)', 'Natural Language :: English', 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Topic :: Scientific/Engineering', 'Topic :: Scientific/Engineering :: Physics', 'Topic :: Software Development :: Libraries', 'Topic :: Utilities' ], **getversion() ) segyio-1.8.3/.gitmodules0000664000372000037200000000014313407674361014612 0ustar travistravis[submodule "multibuild"] path = multibuild url = https://github.com/matthew-brett/multibuild.git