添加实时数据读取
parent
e5f395f716
commit
7a6a34c344
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,61 @@
|
||||
<UserControl x:Class="StartServerWPF.Modules.MseedChart.Views.ChartPlotRealDataView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:converter="clr-namespace:StartServerWPF.Modules.MseedChart.Converters"
|
||||
mc:Ignorable="d" Background="#FFEEF1F3"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True">
|
||||
<UserControl.Resources>
|
||||
<converter:Bool2VisibilityConverter x:Key="Bool2Visibility"/>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="60"/>
|
||||
<RowDefinition Height="50"/>
|
||||
<RowDefinition Height="1000*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="Loaded">
|
||||
<i:InvokeCommandAction Command="{Binding Path=LoadedCommand}"/>
|
||||
</i:EventTrigger>
|
||||
<i:EventTrigger EventName="Unloaded">
|
||||
<i:InvokeCommandAction Command="{Binding Path=UnloadedCommand}"/>
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
<Border Background="White">
|
||||
<TextBlock Text="{Binding Title}" FontSize="16" FontWeight="Bold" VerticalAlignment="Center" Margin="10,0,10,0"/>
|
||||
</Border>
|
||||
<Border Background="White" Grid.Row="1" Grid.RowSpan="2" CornerRadius="5" Margin="10">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50"/>
|
||||
<RowDefinition Height="1000*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!--实时波形-->
|
||||
<StackPanel Orientation="Horizontal" Visibility="{Binding IsRealtimeData,Converter={StaticResource Bool2Visibility}}" Background="White">
|
||||
<Button Grid.Column="1" Grid.Row="1" Command="{Binding RealTimeDataCommand}" CommandParameter="true" Background="#FF3BB4FF" >开始接收</Button>
|
||||
<Button Grid.Column="1" Grid.Row="1" Command="{Binding RealTimeDataCommand}" CommandParameter="false" Background="#FFFFAF20" Margin="20,0,20,0">停止接收</Button>
|
||||
<CheckBox Content="通道选择" x:Name="cBoxAllChannel" IsChecked="{Binding SingleChannel}" VerticalAlignment="Center"/>
|
||||
<ComboBox IsEnabled="{Binding ElementName=cBoxAllChannel, Path=IsChecked}" Text="{Binding SelectChannel}" SelectedIndex="0" VerticalAlignment="Center">
|
||||
<ComboBoxItem Content="SHZ"/>
|
||||
<ComboBoxItem Content="SHN"/>
|
||||
<ComboBoxItem Content="SHE"/>
|
||||
</ComboBox>
|
||||
<TextBlock VerticalAlignment="Center" Margin="20,0,0,0">时间间隔:</TextBlock>
|
||||
<TextBox Text="{Binding XaisInterval}" Width="60" VerticalAlignment="Center"/>
|
||||
<Button Command="{Binding IntervalSureCommand}" Background="#FF66B1FF" HorizontalAlignment="Right">确认</Button>
|
||||
<CheckBox Command="{Binding AxesYVisibleCommand}" Visibility="Collapsed" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=IsChecked}" Content="Y轴显示" VerticalContentAlignment="Center" IsChecked="True" FontSize="15" Foreground="Black" Margin="5,0,5,0" FontWeight="Bold" />
|
||||
<CheckBox Command="{Binding RealTimeDataCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=IsChecked}" Visibility="Collapsed" Content="实时" VerticalContentAlignment="Center" FontSize="15" Foreground="Black" FontWeight="Bold" DockPanel.Dock="Right"></CheckBox>
|
||||
<TextBox Text="{Binding IntervalTime}" Visibility="Collapsed" Width="60" VerticalAlignment="Center"></TextBox>
|
||||
<!--<TextBox Text="{Binding IntervalTime}" Width="60" VerticalAlignment="Center"></TextBox>-->
|
||||
</StackPanel>
|
||||
<ContentControl x:Name="contentControl" Content="{Binding ChildContent}" Grid.Row="1"/>
|
||||
<TextBlock Text="{Binding CurrentTime}" Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="0,0,0,46"></TextBlock>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.AspNetCore.Http" publicKeyToken="adb9793829ddae60" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.2.2.0" newVersion="2.2.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
@ -1,10 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="DryIoc.dll" version="4.7.7" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNetCore.Cryptography.Internal" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNetCore.Cryptography.KeyDerivation" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNetCore.Hosting" version="2.2.7" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNetCore.Hosting.Abstractions" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNetCore.Hosting.Server.Abstractions" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNetCore.Http" version="2.2.2" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNetCore.Http.Abstractions" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNetCore.Http.Extensions" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNetCore.Http.Features" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNetCore.WebUtilities" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="5.0.0" targetFramework="net461" />
|
||||
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Configuration" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Configuration.Abstractions" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Configuration.Binder" version="2.2.4" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Configuration.EnvironmentVariables" version="2.2.4" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Configuration.FileExtensions" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Configuration.Json" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Configuration.UserSecrets" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.DependencyInjection" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.FileProviders.Abstractions" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.FileProviders.Physical" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.FileSystemGlobbing" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Hosting.Abstractions" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Logging" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Logging.Abstractions" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.ObjectPool" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Options" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Extensions.Primitives" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Net.Http.Headers" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.31" targetFramework="net461" />
|
||||
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net461" />
|
||||
<package id="Prism.Core" version="8.1.97" targetFramework="net461" />
|
||||
<package id="Prism.DryIoc" version="8.1.97" targetFramework="net461" />
|
||||
<package id="Prism.Wpf" version="8.1.97" targetFramework="net461" />
|
||||
<package id="ServiceStack" version="6.0.2" targetFramework="net461" />
|
||||
<package id="ServiceStack.Client" version="6.0.2" targetFramework="net461" />
|
||||
<package id="ServiceStack.Common" version="6.0.2" targetFramework="net461" />
|
||||
<package id="ServiceStack.Interfaces" version="6.0.2" targetFramework="net461" />
|
||||
<package id="ServiceStack.Redis" version="6.0.2" targetFramework="net461" />
|
||||
<package id="ServiceStack.Text" version="6.0.2" targetFramework="net461" />
|
||||
<package id="System.Buffers" version="4.5.1" targetFramework="net461" />
|
||||
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
|
||||
<package id="System.Collections.NonGeneric" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Collections.Specialized" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.ComponentModel.Annotations" version="5.0.0" targetFramework="net461" />
|
||||
<package id="System.ComponentModel.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Data.Common" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Diagnostics.DiagnosticSource" version="4.5.1" targetFramework="net461" />
|
||||
<package id="System.Drawing.Common" version="5.0.2" targetFramework="net461" />
|
||||
<package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Linq.Queryable" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Memory" version="4.5.4" targetFramework="net461" />
|
||||
<package id="System.Net.NameResolution" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Net.NetworkInformation" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Net.Requests" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Net.Security" version="4.3.2" targetFramework="net461" />
|
||||
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net461" />
|
||||
<package id="System.Reflection.Emit" version="4.7.0" targetFramework="net461" />
|
||||
<package id="System.Reflection.Metadata" version="1.6.0" targetFramework="net461" />
|
||||
<package id="System.Reflection.TypeExtensions" version="4.7.0" targetFramework="net461" />
|
||||
<package id="System.Runtime" version="4.3.1" targetFramework="net461" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net461" />
|
||||
<package id="System.Runtime.Serialization.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.ServiceModel.Primitives" version="4.8.1" targetFramework="net461" />
|
||||
<package id="System.Text.Encodings.Web" version="4.5.0" targetFramework="net461" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net461" />
|
||||
<package id="System.Threading.Thread" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
|
||||
<package id="System.Xml.XmlSerializer" version="4.3.0" targetFramework="net461" />
|
||||
</packages>
|
@ -0,0 +1,6 @@
|
||||
BasedOnStyle: LLVM
|
||||
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||
SpaceBeforeParens: Always
|
||||
BreakBeforeBraces: Allman
|
||||
AlignConsecutiveAssignments: true
|
||||
ColumnLimit: 0
|
@ -0,0 +1,2 @@
|
||||
doc/working/
|
||||
doc/gh-pages/
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,48 @@
|
||||
|
||||
The library requires that C99 integer types are available on the
|
||||
target computer. Specifically the int8_t, int16_t, int32_t, int64_t
|
||||
and their unsigned counterpart types.
|
||||
|
||||
## Unix, Linux, macOS
|
||||
|
||||
A simple `make` on most Unix-like systems should build the library.
|
||||
|
||||
The included Makefile should work for most Unix-like environments and
|
||||
many make variants. It is known to work with GNU make, which, if not the
|
||||
default, is sometimes installed as `gmake`.
|
||||
|
||||
The `CC`, `CFLAGS`, `LDFLAGS` and `CPPFLAGS` environment variables can be set
|
||||
to control the build.
|
||||
|
||||
If the **LIBMSEED_URL** variable is defined during the build, the library will
|
||||
be compiled with support for reading from URLs. Currently, this support requires
|
||||
that [libcurl](https://curl.haxx.se/) be installed on the target system.
|
||||
|
||||
The simplest way to build the library with URL support is to include `-DLIMSEED_URL`
|
||||
in the CFLAGS environment variable. Or invoking the build as such:
|
||||
|
||||
```
|
||||
CFLAGS+=" -DLIBMSEED_URL" make
|
||||
```
|
||||
|
||||
By default a statically linked version of the library is built: **libmseed.a**,
|
||||
with an accompanying header **libmseed.h**.
|
||||
|
||||
With GCC, clang or compatible build tools it is possible to build a shared
|
||||
library with `make shared`.
|
||||
|
||||
A simple install method for the shared library can be invoked with
|
||||
`make install`. By default the installation destination is /usr/local.
|
||||
The install destination may be specified using the **PREFIX** variable, for
|
||||
example:
|
||||
|
||||
```
|
||||
make install PREFIX=/path/to/install/
|
||||
```
|
||||
|
||||
## Windows
|
||||
|
||||
On a Windows platform the library can be compiled by using the
|
||||
NMake compatible Makefile.win (e.g. 'nmake -f Makefile.win').
|
||||
The default target is a static library 'libmseed.lib'.
|
||||
A libmseed.def file is included for use building and linking a DLL.
|
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -0,0 +1,119 @@
|
||||
|
||||
# Build environment can be configured the following
|
||||
# environment variables:
|
||||
# CC : Specify the C compiler to use
|
||||
# CFLAGS : Specify compiler options to use
|
||||
# LDFLAGS : Specify linker options to use
|
||||
# CPPFLAGS : Specify c-preprocessor options to use
|
||||
|
||||
# Extract version from libmseed.h, expected line should include LIBMSEED_VERSION "#.#.#"
|
||||
MAJOR_VER = $(shell grep LIBMSEED_VERSION libmseed.h | grep -Eo '[0-9]+.[0-9]+.[0-9]+' | cut -d . -f 1)
|
||||
FULL_VER = $(shell grep LIBMSEED_VERSION libmseed.h | grep -Eo '[0-9]+.[0-9]+.[0-9]+')
|
||||
COMPAT_VER = $(MAJOR_VER).0.0
|
||||
|
||||
# Default settings for install target
|
||||
PREFIX ?= /usr/local
|
||||
EXEC_PREFIX ?= $(PREFIX)
|
||||
LIBDIR ?= $(EXEC_PREFIX)/lib
|
||||
INCLUDEDIR ?= $(PREFIX)/include
|
||||
DATAROOTDIR ?= $(PREFIX)/share
|
||||
DOCDIR ?= $(DATAROOTDIR)/doc/libmseed
|
||||
MANDIR ?= $(DATAROOTDIR)/man
|
||||
MAN3DIR ?= $(MANDIR)/man3
|
||||
|
||||
LIB_SRCS = fileutils.c genutils.c msio.c lookup.c yyjson.c msrutils.c \
|
||||
extraheaders.c pack.c packdata.c tracelist.c gmtime64.c crc32c.c \
|
||||
parseutils.c unpack.c unpackdata.c selection.c logging.c
|
||||
|
||||
LIB_OBJS = $(LIB_SRCS:.c=.o)
|
||||
LIB_LOBJS = $(LIB_SRCS:.c=.lo)
|
||||
|
||||
LIB_NAME = libmseed
|
||||
LIB_A = $(LIB_NAME).a
|
||||
|
||||
OS := $(shell uname -s)
|
||||
|
||||
# Build dynamic (.dylib) on macOS/Darwin, otherwise shared (.so)
|
||||
ifeq ($(OS), Darwin)
|
||||
LIB_SO_BASE = $(LIB_NAME).dylib
|
||||
LIB_SO_MAJOR = $(LIB_NAME).$(MAJOR_VER).dylib
|
||||
LIB_SO = $(LIB_NAME).$(FULL_VER).dylib
|
||||
LIB_OPTS = -dynamiclib -compatibility_version $(COMPAT_VER) -current_version $(FULL_VER) -install_name $(LIB_SO)
|
||||
else
|
||||
LIB_SO_BASE = $(LIB_NAME).so
|
||||
LIB_SO_MAJOR = $(LIB_NAME).so.$(MAJOR_VER)
|
||||
LIB_SO = $(LIB_NAME).so.$(FULL_VER)
|
||||
LIB_OPTS = -shared -Wl,--version-script=libmseed.map -Wl,-soname,$(LIB_SO_MAJOR)
|
||||
endif
|
||||
|
||||
# Automatically configure LDFLAGS for URL support if requested and libcurl is available
|
||||
# Test for LIBMSEED_URL in CFLAGS, then if curl-config is available, implying libcurl is available
|
||||
ifneq (,$(findstring LIBMSEED_URL,$(CFLAGS)))
|
||||
ifneq (,$(shell command -v curl-config;))
|
||||
export LM_CURL_VERSION=$(shell curl-config --version)
|
||||
export LDLIBS:=$(LDLIBS) $(shell curl-config --libs)
|
||||
endif
|
||||
endif
|
||||
|
||||
all: static
|
||||
|
||||
static: $(LIB_A)
|
||||
|
||||
shared dynamic: $(LIB_SO)
|
||||
|
||||
# Build static library
|
||||
$(LIB_A): $(LIB_OBJS)
|
||||
@echo "Building static library $(LIB_A)"
|
||||
$(RM) -f $(LIB_A)
|
||||
$(AR) -crs $(LIB_A) $(LIB_OBJS)
|
||||
|
||||
# Build shared/dynamic library
|
||||
$(LIB_SO): $(LIB_LOBJS)
|
||||
@echo "Building shared library $(LIB_SO)"
|
||||
$(RM) -f $(LIB_SO) $(LIB_SO_MAJOR) $(LIB_SO_BASE)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) $(LIB_OPTS) -o $(LIB_SO) $(LIB_LOBJS)
|
||||
ln -s $(LIB_SO) $(LIB_SO_BASE)
|
||||
ln -s $(LIB_SO) $(LIB_SO_MAJOR)
|
||||
|
||||
test check: static FORCE
|
||||
@$(MAKE) -C test test
|
||||
|
||||
example: static FORCE
|
||||
@$(MAKE) -C example
|
||||
|
||||
clean:
|
||||
@$(RM) $(LIB_OBJS) $(LIB_LOBJS) $(LIB_A) $(LIB_SO) $(LIB_SO_MAJOR) $(LIB_SO_BASE)
|
||||
@$(MAKE) -C test clean
|
||||
@$(MAKE) -C example clean
|
||||
@echo "All clean."
|
||||
|
||||
install: shared
|
||||
@echo "Installing into $(PREFIX)"
|
||||
@mkdir -p $(DESTDIR)$(PREFIX)/include
|
||||
@cp libmseed.h $(DESTDIR)$(PREFIX)/include
|
||||
@mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig
|
||||
@cp -a $(LIB_SO_BASE) $(LIB_SO_MAJOR) $(LIB_SO_NAME) $(LIB_SO) $(DESTDIR)$(LIBDIR)
|
||||
@sed -e 's|@PREFIX@|$(PREFIX)|g' \
|
||||
-e 's|@EXEC_PREFIX@|$(EXEC_PREFIX)|g' \
|
||||
-e 's|@LIBDIR@|$(LIBDIR)|g' \
|
||||
-e 's|@INCLUDEDIR@|$(PREFIX)/include|g' \
|
||||
-e 's|@VERSION@|$(FULL_VER)|g' \
|
||||
mseed.pc.in > $(DESTDIR)$(LIBDIR)/pkgconfig/mseed.pc
|
||||
@mkdir -p $(DESTDIR)$(DOCDIR)/example
|
||||
@cp -r example $(DESTDIR)$(DOCDIR)/
|
||||
|
||||
.SUFFIXES: .c .o .lo
|
||||
|
||||
# Standard object building
|
||||
.c.o:
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Standard object building for shared library using -fPIC
|
||||
.c.lo:
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -c $< -o $@
|
||||
|
||||
# Print Makefile expanded variables, e.g. % make print-LIB_SO
|
||||
print-%:
|
||||
@echo '$*=$($*)'
|
||||
|
||||
FORCE:
|
@ -0,0 +1,49 @@
|
||||
#
|
||||
# Nmake file for libmseed - MS Visual C/C++
|
||||
# Use 'nmake -f Makefile.win'
|
||||
|
||||
NODEBUG=1
|
||||
|
||||
INCS = /I.
|
||||
OPTS = /O2 /D_CRT_SECURE_NO_WARNINGS
|
||||
LM_LIB = libmseed.lib
|
||||
LM_DLL = libmseed.dll
|
||||
LM_DEF = libmseed.def
|
||||
|
||||
OBJS = fileutils.obj \
|
||||
genutils.obj \
|
||||
msio.obj \
|
||||
lookup.obj \
|
||||
yyjson.obj \
|
||||
msrutils.obj \
|
||||
extraheaders.obj\
|
||||
pack.obj \
|
||||
packdata.obj \
|
||||
tracelist.obj \
|
||||
gmtime64.obj \
|
||||
crc32c.obj \
|
||||
parseutils.obj \
|
||||
unpack.obj \
|
||||
unpackdata.obj \
|
||||
selection.obj \
|
||||
logging.obj
|
||||
|
||||
all: lib
|
||||
|
||||
lib: $(OBJS)
|
||||
link.exe /lib /nologo /OUT:$(LM_LIB) $(OBJS)
|
||||
|
||||
dll: $(OBJS)
|
||||
link.exe /dll /nologo /OUT:$(LM_DLL) $(OBJS)
|
||||
|
||||
.c.obj:
|
||||
$(CC) /nologo $(CFLAGS) $(INCS) $(OPTS) /c $<
|
||||
|
||||
# Run test suite
|
||||
test: lib
|
||||
pushd $@ && $(MAKE) /NOLOGO /f Makefile.win /$(MAKEFLAGS) & popd
|
||||
|
||||
# Clean-up directives
|
||||
clean:
|
||||
-del a.out core *.o *.obj *% *~ libmseed.exp $(LM_LIB) $(LM_DLL)
|
||||
@pushd test && $(MAKE) /NOLOGO /f Makefile.win $@ /$(MAKEFLAGS) & popd
|
@ -0,0 +1,25 @@
|
||||
|
||||
-- Byte order handling in libmseed --
|
||||
|
||||
The miniSEED 3 format is defined as little-endian headers with the
|
||||
endianess of the data payload explicitly defined by the encoding
|
||||
value.
|
||||
|
||||
The SEED 2.4 standard allows data only SEED (miniSEED) to be either in
|
||||
big (most significant byte first) or little (least significant byte
|
||||
first) endian byte order. One exception is that Steim-1 and Steim-2
|
||||
data compression are only defined as big-endian.
|
||||
|
||||
How libmseed determines the byte order of a 2.x record:
|
||||
|
||||
The byte order of a miniSEED 2.x record header including blockettes is
|
||||
determined by checking if the record start year and day is a sane
|
||||
value (e.g. year between 1900 and 2100 and day between 1 and 366).
|
||||
The byte order of encoded data samples is determined by the byte order
|
||||
flag in the Blockette 1000, if a Blockette 1000 is not present the
|
||||
byte order is assumed to be the same as the header.
|
||||
|
||||
In what byte order libmseed creates 2.x records:
|
||||
|
||||
If the library ever creates miniSEED 2.x records, they will be in
|
||||
big-endian byte order for maximum compatibility.
|
@ -0,0 +1,32 @@
|
||||
|
||||
# libmseed - The miniSEED library
|
||||
|
||||
The miniSEED library provides a framework for manipulation of SEED
|
||||
data records, a format for commonly used for seismological time series
|
||||
and related data. The library includes the functionality to read and
|
||||
write data records, in addition to reconstructing time series from
|
||||
multiple records.
|
||||
|
||||
The library should work in Unix-like, Windows and potentially other
|
||||
environments.
|
||||
|
||||
## Documentation
|
||||
|
||||
The [Documentation](https://earthscope.github.io/libmseed) provides an
|
||||
overview of using the library, a tutorial and function level details.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Copyright (C) 2023 Chad Trabant, EarthScope Data Services
|
@ -0,0 +1,410 @@
|
||||
/***************************************************************************
|
||||
* CRC-32C calculation routines, clean and simple. Orignal file was named
|
||||
* 'crc_sw.c' and found at: https://github.com/awslabs/aws-checksums
|
||||
*
|
||||
* All copyrights and license notifications have been retained.
|
||||
* Unecessary routines have been removed for use in this code base.
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#include "libmseed.h"
|
||||
|
||||
/* The Castagnoli, iSCSI CRC32c polynomial (reverse of 0x1EDC6F41) */
|
||||
#define CRC32C_POLYNOMIAL 0x82F63B78
|
||||
|
||||
/** Castagnoli CRC32c (iSCSI) lookup table for slice-by-4/8/16 */
|
||||
/* Table truncated to 8 top-level tables from original, slice-by-16 is not supported in this code */
|
||||
const uint32_t CRC32C_TABLE[8][256] = {
|
||||
{
|
||||
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, // [0][0x08]
|
||||
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, // [0][0x10]
|
||||
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, // [0][0x18]
|
||||
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, // [0][0x20]
|
||||
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, // [0][0x28]
|
||||
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, // [0][0x30]
|
||||
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, // [0][0x38]
|
||||
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, // [0][0x40]
|
||||
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, // [0][0x48]
|
||||
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, // [0][0x50]
|
||||
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, // [0][0x58]
|
||||
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, // [0][0x60]
|
||||
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, // [0][0x68]
|
||||
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, // [0][0x70]
|
||||
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, // [0][0x78]
|
||||
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, // [0][0x80]
|
||||
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, // [0][0x88]
|
||||
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, // [0][0x90]
|
||||
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, // [0][0x98]
|
||||
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, // [0][0xa0]
|
||||
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, // [0][0xa8]
|
||||
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, // [0][0xb0]
|
||||
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, // [0][0xb8]
|
||||
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, // [0][0xc0]
|
||||
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, // [0][0xc8]
|
||||
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, // [0][0xd0]
|
||||
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, // [0][0xd8]
|
||||
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, // [0][0xe0]
|
||||
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, // [0][0xe8]
|
||||
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, // [0][0xf0]
|
||||
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, // [0][0xf8]
|
||||
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 // [0][0x100]
|
||||
},
|
||||
{
|
||||
0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, // [1][0x08]
|
||||
0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, // [1][0x10]
|
||||
0x3FC5F181, 0x2C6769F6, 0x1880C16F, 0x0B225918, 0x714F905D, 0x62ED082A, 0x560AA0B3, 0x45A838C4, // [1][0x18]
|
||||
0xA2D13239, 0xB173AA4E, 0x859402D7, 0x96369AA0, 0xEC5B53E5, 0xFFF9CB92, 0xCB1E630B, 0xD8BCFB7C, // [1][0x20]
|
||||
0x7F8BE302, 0x6C297B75, 0x58CED3EC, 0x4B6C4B9B, 0x310182DE, 0x22A31AA9, 0x1644B230, 0x05E62A47, // [1][0x28]
|
||||
0xE29F20BA, 0xF13DB8CD, 0xC5DA1054, 0xD6788823, 0xAC154166, 0xBFB7D911, 0x8B507188, 0x98F2E9FF, // [1][0x30]
|
||||
0x404E1283, 0x53EC8AF4, 0x670B226D, 0x74A9BA1A, 0x0EC4735F, 0x1D66EB28, 0x298143B1, 0x3A23DBC6, // [1][0x38]
|
||||
0xDD5AD13B, 0xCEF8494C, 0xFA1FE1D5, 0xE9BD79A2, 0x93D0B0E7, 0x80722890, 0xB4958009, 0xA737187E, // [1][0x40]
|
||||
0xFF17C604, 0xECB55E73, 0xD852F6EA, 0xCBF06E9D, 0xB19DA7D8, 0xA23F3FAF, 0x96D89736, 0x857A0F41, // [1][0x48]
|
||||
0x620305BC, 0x71A19DCB, 0x45463552, 0x56E4AD25, 0x2C896460, 0x3F2BFC17, 0x0BCC548E, 0x186ECCF9, // [1][0x50]
|
||||
0xC0D23785, 0xD370AFF2, 0xE797076B, 0xF4359F1C, 0x8E585659, 0x9DFACE2E, 0xA91D66B7, 0xBABFFEC0, // [1][0x58]
|
||||
0x5DC6F43D, 0x4E646C4A, 0x7A83C4D3, 0x69215CA4, 0x134C95E1, 0x00EE0D96, 0x3409A50F, 0x27AB3D78, // [1][0x60]
|
||||
0x809C2506, 0x933EBD71, 0xA7D915E8, 0xB47B8D9F, 0xCE1644DA, 0xDDB4DCAD, 0xE9537434, 0xFAF1EC43, // [1][0x68]
|
||||
0x1D88E6BE, 0x0E2A7EC9, 0x3ACDD650, 0x296F4E27, 0x53028762, 0x40A01F15, 0x7447B78C, 0x67E52FFB, // [1][0x70]
|
||||
0xBF59D487, 0xACFB4CF0, 0x981CE469, 0x8BBE7C1E, 0xF1D3B55B, 0xE2712D2C, 0xD69685B5, 0xC5341DC2, // [1][0x78]
|
||||
0x224D173F, 0x31EF8F48, 0x050827D1, 0x16AABFA6, 0x6CC776E3, 0x7F65EE94, 0x4B82460D, 0x5820DE7A, // [1][0x80]
|
||||
0xFBC3FAF9, 0xE861628E, 0xDC86CA17, 0xCF245260, 0xB5499B25, 0xA6EB0352, 0x920CABCB, 0x81AE33BC, // [1][0x88]
|
||||
0x66D73941, 0x7575A136, 0x419209AF, 0x523091D8, 0x285D589D, 0x3BFFC0EA, 0x0F186873, 0x1CBAF004, // [1][0x90]
|
||||
0xC4060B78, 0xD7A4930F, 0xE3433B96, 0xF0E1A3E1, 0x8A8C6AA4, 0x992EF2D3, 0xADC95A4A, 0xBE6BC23D, // [1][0x98]
|
||||
0x5912C8C0, 0x4AB050B7, 0x7E57F82E, 0x6DF56059, 0x1798A91C, 0x043A316B, 0x30DD99F2, 0x237F0185, // [1][0xa0]
|
||||
0x844819FB, 0x97EA818C, 0xA30D2915, 0xB0AFB162, 0xCAC27827, 0xD960E050, 0xED8748C9, 0xFE25D0BE, // [1][0xa8]
|
||||
0x195CDA43, 0x0AFE4234, 0x3E19EAAD, 0x2DBB72DA, 0x57D6BB9F, 0x447423E8, 0x70938B71, 0x63311306, // [1][0xb0]
|
||||
0xBB8DE87A, 0xA82F700D, 0x9CC8D894, 0x8F6A40E3, 0xF50789A6, 0xE6A511D1, 0xD242B948, 0xC1E0213F, // [1][0xb8]
|
||||
0x26992BC2, 0x353BB3B5, 0x01DC1B2C, 0x127E835B, 0x68134A1E, 0x7BB1D269, 0x4F567AF0, 0x5CF4E287, // [1][0xc0]
|
||||
0x04D43CFD, 0x1776A48A, 0x23910C13, 0x30339464, 0x4A5E5D21, 0x59FCC556, 0x6D1B6DCF, 0x7EB9F5B8, // [1][0xc8]
|
||||
0x99C0FF45, 0x8A626732, 0xBE85CFAB, 0xAD2757DC, 0xD74A9E99, 0xC4E806EE, 0xF00FAE77, 0xE3AD3600, // [1][0xd0]
|
||||
0x3B11CD7C, 0x28B3550B, 0x1C54FD92, 0x0FF665E5, 0x759BACA0, 0x663934D7, 0x52DE9C4E, 0x417C0439, // [1][0xd8]
|
||||
0xA6050EC4, 0xB5A796B3, 0x81403E2A, 0x92E2A65D, 0xE88F6F18, 0xFB2DF76F, 0xCFCA5FF6, 0xDC68C781, // [1][0xe0]
|
||||
0x7B5FDFFF, 0x68FD4788, 0x5C1AEF11, 0x4FB87766, 0x35D5BE23, 0x26772654, 0x12908ECD, 0x013216BA, // [1][0xe8]
|
||||
0xE64B1C47, 0xF5E98430, 0xC10E2CA9, 0xD2ACB4DE, 0xA8C17D9B, 0xBB63E5EC, 0x8F844D75, 0x9C26D502, // [1][0xf0]
|
||||
0x449A2E7E, 0x5738B609, 0x63DF1E90, 0x707D86E7, 0x0A104FA2, 0x19B2D7D5, 0x2D557F4C, 0x3EF7E73B, // [1][0xf8]
|
||||
0xD98EEDC6, 0xCA2C75B1, 0xFECBDD28, 0xED69455F, 0x97048C1A, 0x84A6146D, 0xB041BCF4, 0xA3E32483 // [1][0x100]
|
||||
},
|
||||
{
|
||||
0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, // [2][0x08]
|
||||
0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, // [2][0x10]
|
||||
0x70A27D8A, 0xD5E3EFF4, 0x3FCD2F87, 0x9A8CBDF9, 0xEE7CD990, 0x4B3D4BEE, 0xA1138B9D, 0x045219E3, // [2][0x18]
|
||||
0x48F3434F, 0xEDB2D131, 0x079C1142, 0xA2DD833C, 0xD62DE755, 0x736C752B, 0x9942B558, 0x3C032726, // [2][0x20]
|
||||
0xE144FB14, 0x4405696A, 0xAE2BA919, 0x0B6A3B67, 0x7F9A5F0E, 0xDADBCD70, 0x30F50D03, 0x95B49F7D, // [2][0x28]
|
||||
0xD915C5D1, 0x7C5457AF, 0x967A97DC, 0x333B05A2, 0x47CB61CB, 0xE28AF3B5, 0x08A433C6, 0xADE5A1B8, // [2][0x30]
|
||||
0x91E6869E, 0x34A714E0, 0xDE89D493, 0x7BC846ED, 0x0F382284, 0xAA79B0FA, 0x40577089, 0xE516E2F7, // [2][0x38]
|
||||
0xA9B7B85B, 0x0CF62A25, 0xE6D8EA56, 0x43997828, 0x37691C41, 0x92288E3F, 0x78064E4C, 0xDD47DC32, // [2][0x40]
|
||||
0xC76580D9, 0x622412A7, 0x880AD2D4, 0x2D4B40AA, 0x59BB24C3, 0xFCFAB6BD, 0x16D476CE, 0xB395E4B0, // [2][0x48]
|
||||
0xFF34BE1C, 0x5A752C62, 0xB05BEC11, 0x151A7E6F, 0x61EA1A06, 0xC4AB8878, 0x2E85480B, 0x8BC4DA75, // [2][0x50]
|
||||
0xB7C7FD53, 0x12866F2D, 0xF8A8AF5E, 0x5DE93D20, 0x29195949, 0x8C58CB37, 0x66760B44, 0xC337993A, // [2][0x58]
|
||||
0x8F96C396, 0x2AD751E8, 0xC0F9919B, 0x65B803E5, 0x1148678C, 0xB409F5F2, 0x5E273581, 0xFB66A7FF, // [2][0x60]
|
||||
0x26217BCD, 0x8360E9B3, 0x694E29C0, 0xCC0FBBBE, 0xB8FFDFD7, 0x1DBE4DA9, 0xF7908DDA, 0x52D11FA4, // [2][0x68]
|
||||
0x1E704508, 0xBB31D776, 0x511F1705, 0xF45E857B, 0x80AEE112, 0x25EF736C, 0xCFC1B31F, 0x6A802161, // [2][0x70]
|
||||
0x56830647, 0xF3C29439, 0x19EC544A, 0xBCADC634, 0xC85DA25D, 0x6D1C3023, 0x8732F050, 0x2273622E, // [2][0x78]
|
||||
0x6ED23882, 0xCB93AAFC, 0x21BD6A8F, 0x84FCF8F1, 0xF00C9C98, 0x554D0EE6, 0xBF63CE95, 0x1A225CEB, // [2][0x80]
|
||||
0x8B277743, 0x2E66E53D, 0xC448254E, 0x6109B730, 0x15F9D359, 0xB0B84127, 0x5A968154, 0xFFD7132A, // [2][0x88]
|
||||
0xB3764986, 0x1637DBF8, 0xFC191B8B, 0x595889F5, 0x2DA8ED9C, 0x88E97FE2, 0x62C7BF91, 0xC7862DEF, // [2][0x90]
|
||||
0xFB850AC9, 0x5EC498B7, 0xB4EA58C4, 0x11ABCABA, 0x655BAED3, 0xC01A3CAD, 0x2A34FCDE, 0x8F756EA0, // [2][0x98]
|
||||
0xC3D4340C, 0x6695A672, 0x8CBB6601, 0x29FAF47F, 0x5D0A9016, 0xF84B0268, 0x1265C21B, 0xB7245065, // [2][0xa0]
|
||||
0x6A638C57, 0xCF221E29, 0x250CDE5A, 0x804D4C24, 0xF4BD284D, 0x51FCBA33, 0xBBD27A40, 0x1E93E83E, // [2][0xa8]
|
||||
0x5232B292, 0xF77320EC, 0x1D5DE09F, 0xB81C72E1, 0xCCEC1688, 0x69AD84F6, 0x83834485, 0x26C2D6FB, // [2][0xb0]
|
||||
0x1AC1F1DD, 0xBF8063A3, 0x55AEA3D0, 0xF0EF31AE, 0x841F55C7, 0x215EC7B9, 0xCB7007CA, 0x6E3195B4, // [2][0xb8]
|
||||
0x2290CF18, 0x87D15D66, 0x6DFF9D15, 0xC8BE0F6B, 0xBC4E6B02, 0x190FF97C, 0xF321390F, 0x5660AB71, // [2][0xc0]
|
||||
0x4C42F79A, 0xE90365E4, 0x032DA597, 0xA66C37E9, 0xD29C5380, 0x77DDC1FE, 0x9DF3018D, 0x38B293F3, // [2][0xc8]
|
||||
0x7413C95F, 0xD1525B21, 0x3B7C9B52, 0x9E3D092C, 0xEACD6D45, 0x4F8CFF3B, 0xA5A23F48, 0x00E3AD36, // [2][0xd0]
|
||||
0x3CE08A10, 0x99A1186E, 0x738FD81D, 0xD6CE4A63, 0xA23E2E0A, 0x077FBC74, 0xED517C07, 0x4810EE79, // [2][0xd8]
|
||||
0x04B1B4D5, 0xA1F026AB, 0x4BDEE6D8, 0xEE9F74A6, 0x9A6F10CF, 0x3F2E82B1, 0xD50042C2, 0x7041D0BC, // [2][0xe0]
|
||||
0xAD060C8E, 0x08479EF0, 0xE2695E83, 0x4728CCFD, 0x33D8A894, 0x96993AEA, 0x7CB7FA99, 0xD9F668E7, // [2][0xe8]
|
||||
0x9557324B, 0x3016A035, 0xDA386046, 0x7F79F238, 0x0B899651, 0xAEC8042F, 0x44E6C45C, 0xE1A75622, // [2][0xf0]
|
||||
0xDDA47104, 0x78E5E37A, 0x92CB2309, 0x378AB177, 0x437AD51E, 0xE63B4760, 0x0C158713, 0xA954156D, // [2][0xf8]
|
||||
0xE5F54FC1, 0x40B4DDBF, 0xAA9A1DCC, 0x0FDB8FB2, 0x7B2BEBDB, 0xDE6A79A5, 0x3444B9D6, 0x91052BA8 // [2][0x100]
|
||||
},
|
||||
{
|
||||
0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, // [3][0x08]
|
||||
0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, // [3][0x10]
|
||||
0xE964B13D, 0x34211B85, 0x560392BC, 0x8B463804, 0x924680CE, 0x4F032A76, 0x2D21A34F, 0xF06409F7, // [3][0x18]
|
||||
0x1F20D2DB, 0xC2657863, 0xA047F15A, 0x7D025BE2, 0x6402E328, 0xB9474990, 0xDB65C0A9, 0x06206A11, // [3][0x20]
|
||||
0xD725148B, 0x0A60BE33, 0x6842370A, 0xB5079DB2, 0xAC072578, 0x71428FC0, 0x136006F9, 0xCE25AC41, // [3][0x28]
|
||||
0x2161776D, 0xFC24DDD5, 0x9E0654EC, 0x4343FE54, 0x5A43469E, 0x8706EC26, 0xE524651F, 0x3861CFA7, // [3][0x30]
|
||||
0x3E41A5B6, 0xE3040F0E, 0x81268637, 0x5C632C8F, 0x45639445, 0x98263EFD, 0xFA04B7C4, 0x27411D7C, // [3][0x38]
|
||||
0xC805C650, 0x15406CE8, 0x7762E5D1, 0xAA274F69, 0xB327F7A3, 0x6E625D1B, 0x0C40D422, 0xD1057E9A, // [3][0x40]
|
||||
0xABA65FE7, 0x76E3F55F, 0x14C17C66, 0xC984D6DE, 0xD0846E14, 0x0DC1C4AC, 0x6FE34D95, 0xB2A6E72D, // [3][0x48]
|
||||
0x5DE23C01, 0x80A796B9, 0xE2851F80, 0x3FC0B538, 0x26C00DF2, 0xFB85A74A, 0x99A72E73, 0x44E284CB, // [3][0x50]
|
||||
0x42C2EEDA, 0x9F874462, 0xFDA5CD5B, 0x20E067E3, 0x39E0DF29, 0xE4A57591, 0x8687FCA8, 0x5BC25610, // [3][0x58]
|
||||
0xB4868D3C, 0x69C32784, 0x0BE1AEBD, 0xD6A40405, 0xCFA4BCCF, 0x12E11677, 0x70C39F4E, 0xAD8635F6, // [3][0x60]
|
||||
0x7C834B6C, 0xA1C6E1D4, 0xC3E468ED, 0x1EA1C255, 0x07A17A9F, 0xDAE4D027, 0xB8C6591E, 0x6583F3A6, // [3][0x68]
|
||||
0x8AC7288A, 0x57828232, 0x35A00B0B, 0xE8E5A1B3, 0xF1E51979, 0x2CA0B3C1, 0x4E823AF8, 0x93C79040, // [3][0x70]
|
||||
0x95E7FA51, 0x48A250E9, 0x2A80D9D0, 0xF7C57368, 0xEEC5CBA2, 0x3380611A, 0x51A2E823, 0x8CE7429B, // [3][0x78]
|
||||
0x63A399B7, 0xBEE6330F, 0xDCC4BA36, 0x0181108E, 0x1881A844, 0xC5C402FC, 0xA7E68BC5, 0x7AA3217D, // [3][0x80]
|
||||
0x52A0C93F, 0x8FE56387, 0xEDC7EABE, 0x30824006, 0x2982F8CC, 0xF4C75274, 0x96E5DB4D, 0x4BA071F5, // [3][0x88]
|
||||
0xA4E4AAD9, 0x79A10061, 0x1B838958, 0xC6C623E0, 0xDFC69B2A, 0x02833192, 0x60A1B8AB, 0xBDE41213, // [3][0x90]
|
||||
0xBBC47802, 0x6681D2BA, 0x04A35B83, 0xD9E6F13B, 0xC0E649F1, 0x1DA3E349, 0x7F816A70, 0xA2C4C0C8, // [3][0x98]
|
||||
0x4D801BE4, 0x90C5B15C, 0xF2E73865, 0x2FA292DD, 0x36A22A17, 0xEBE780AF, 0x89C50996, 0x5480A32E, // [3][0xa0]
|
||||
0x8585DDB4, 0x58C0770C, 0x3AE2FE35, 0xE7A7548D, 0xFEA7EC47, 0x23E246FF, 0x41C0CFC6, 0x9C85657E, // [3][0xa8]
|
||||
0x73C1BE52, 0xAE8414EA, 0xCCA69DD3, 0x11E3376B, 0x08E38FA1, 0xD5A62519, 0xB784AC20, 0x6AC10698, // [3][0xb0]
|
||||
0x6CE16C89, 0xB1A4C631, 0xD3864F08, 0x0EC3E5B0, 0x17C35D7A, 0xCA86F7C2, 0xA8A47EFB, 0x75E1D443, // [3][0xb8]
|
||||
0x9AA50F6F, 0x47E0A5D7, 0x25C22CEE, 0xF8878656, 0xE1873E9C, 0x3CC29424, 0x5EE01D1D, 0x83A5B7A5, // [3][0xc0]
|
||||
0xF90696D8, 0x24433C60, 0x4661B559, 0x9B241FE1, 0x8224A72B, 0x5F610D93, 0x3D4384AA, 0xE0062E12, // [3][0xc8]
|
||||
0x0F42F53E, 0xD2075F86, 0xB025D6BF, 0x6D607C07, 0x7460C4CD, 0xA9256E75, 0xCB07E74C, 0x16424DF4, // [3][0xd0]
|
||||
0x106227E5, 0xCD278D5D, 0xAF050464, 0x7240AEDC, 0x6B401616, 0xB605BCAE, 0xD4273597, 0x09629F2F, // [3][0xd8]
|
||||
0xE6264403, 0x3B63EEBB, 0x59416782, 0x8404CD3A, 0x9D0475F0, 0x4041DF48, 0x22635671, 0xFF26FCC9, // [3][0xe0]
|
||||
0x2E238253, 0xF36628EB, 0x9144A1D2, 0x4C010B6A, 0x5501B3A0, 0x88441918, 0xEA669021, 0x37233A99, // [3][0xe8]
|
||||
0xD867E1B5, 0x05224B0D, 0x6700C234, 0xBA45688C, 0xA345D046, 0x7E007AFE, 0x1C22F3C7, 0xC167597F, // [3][0xf0]
|
||||
0xC747336E, 0x1A0299D6, 0x782010EF, 0xA565BA57, 0xBC65029D, 0x6120A825, 0x0302211C, 0xDE478BA4, // [3][0xf8]
|
||||
0x31035088, 0xEC46FA30, 0x8E647309, 0x5321D9B1, 0x4A21617B, 0x9764CBC3, 0xF54642FA, 0x2803E842 // [3][0x100]
|
||||
},
|
||||
{
|
||||
0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, // [4][0x08]
|
||||
0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, // [4][0x10]
|
||||
0x8F2261D3, 0xB7330E7F, 0xFF00BE8B, 0xC711D127, 0x6F67DF63, 0x5776B0CF, 0x1F45003B, 0x27546F97, // [4][0x18]
|
||||
0x4A456A42, 0x725405EE, 0x3A67B51A, 0x0276DAB6, 0xAA00D4F2, 0x9211BB5E, 0xDA220BAA, 0xE2336406, // [4][0x20]
|
||||
0x1BA8B557, 0x23B9DAFB, 0x6B8A6A0F, 0x539B05A3, 0xFBED0BE7, 0xC3FC644B, 0x8BCFD4BF, 0xB3DEBB13, // [4][0x28]
|
||||
0xDECFBEC6, 0xE6DED16A, 0xAEED619E, 0x96FC0E32, 0x3E8A0076, 0x069B6FDA, 0x4EA8DF2E, 0x76B9B082, // [4][0x30]
|
||||
0x948AD484, 0xAC9BBB28, 0xE4A80BDC, 0xDCB96470, 0x74CF6A34, 0x4CDE0598, 0x04EDB56C, 0x3CFCDAC0, // [4][0x38]
|
||||
0x51EDDF15, 0x69FCB0B9, 0x21CF004D, 0x19DE6FE1, 0xB1A861A5, 0x89B90E09, 0xC18ABEFD, 0xF99BD151, // [4][0x40]
|
||||
0x37516AAE, 0x0F400502, 0x4773B5F6, 0x7F62DA5A, 0xD714D41E, 0xEF05BBB2, 0xA7360B46, 0x9F2764EA, // [4][0x48]
|
||||
0xF236613F, 0xCA270E93, 0x8214BE67, 0xBA05D1CB, 0x1273DF8F, 0x2A62B023, 0x625100D7, 0x5A406F7B, // [4][0x50]
|
||||
0xB8730B7D, 0x806264D1, 0xC851D425, 0xF040BB89, 0x5836B5CD, 0x6027DA61, 0x28146A95, 0x10050539, // [4][0x58]
|
||||
0x7D1400EC, 0x45056F40, 0x0D36DFB4, 0x3527B018, 0x9D51BE5C, 0xA540D1F0, 0xED736104, 0xD5620EA8, // [4][0x60]
|
||||
0x2CF9DFF9, 0x14E8B055, 0x5CDB00A1, 0x64CA6F0D, 0xCCBC6149, 0xF4AD0EE5, 0xBC9EBE11, 0x848FD1BD, // [4][0x68]
|
||||
0xE99ED468, 0xD18FBBC4, 0x99BC0B30, 0xA1AD649C, 0x09DB6AD8, 0x31CA0574, 0x79F9B580, 0x41E8DA2C, // [4][0x70]
|
||||
0xA3DBBE2A, 0x9BCAD186, 0xD3F96172, 0xEBE80EDE, 0x439E009A, 0x7B8F6F36, 0x33BCDFC2, 0x0BADB06E, // [4][0x78]
|
||||
0x66BCB5BB, 0x5EADDA17, 0x169E6AE3, 0x2E8F054F, 0x86F90B0B, 0xBEE864A7, 0xF6DBD453, 0xCECABBFF, // [4][0x80]
|
||||
0x6EA2D55C, 0x56B3BAF0, 0x1E800A04, 0x269165A8, 0x8EE76BEC, 0xB6F60440, 0xFEC5B4B4, 0xC6D4DB18, // [4][0x88]
|
||||
0xABC5DECD, 0x93D4B161, 0xDBE70195, 0xE3F66E39, 0x4B80607D, 0x73910FD1, 0x3BA2BF25, 0x03B3D089, // [4][0x90]
|
||||
0xE180B48F, 0xD991DB23, 0x91A26BD7, 0xA9B3047B, 0x01C50A3F, 0x39D46593, 0x71E7D567, 0x49F6BACB, // [4][0x98]
|
||||
0x24E7BF1E, 0x1CF6D0B2, 0x54C56046, 0x6CD40FEA, 0xC4A201AE, 0xFCB36E02, 0xB480DEF6, 0x8C91B15A, // [4][0xa0]
|
||||
0x750A600B, 0x4D1B0FA7, 0x0528BF53, 0x3D39D0FF, 0x954FDEBB, 0xAD5EB117, 0xE56D01E3, 0xDD7C6E4F, // [4][0xa8]
|
||||
0xB06D6B9A, 0x887C0436, 0xC04FB4C2, 0xF85EDB6E, 0x5028D52A, 0x6839BA86, 0x200A0A72, 0x181B65DE, // [4][0xb0]
|
||||
0xFA2801D8, 0xC2396E74, 0x8A0ADE80, 0xB21BB12C, 0x1A6DBF68, 0x227CD0C4, 0x6A4F6030, 0x525E0F9C, // [4][0xb8]
|
||||
0x3F4F0A49, 0x075E65E5, 0x4F6DD511, 0x777CBABD, 0xDF0AB4F9, 0xE71BDB55, 0xAF286BA1, 0x9739040D, // [4][0xc0]
|
||||
0x59F3BFF2, 0x61E2D05E, 0x29D160AA, 0x11C00F06, 0xB9B60142, 0x81A76EEE, 0xC994DE1A, 0xF185B1B6, // [4][0xc8]
|
||||
0x9C94B463, 0xA485DBCF, 0xECB66B3B, 0xD4A70497, 0x7CD10AD3, 0x44C0657F, 0x0CF3D58B, 0x34E2BA27, // [4][0xd0]
|
||||
0xD6D1DE21, 0xEEC0B18D, 0xA6F30179, 0x9EE26ED5, 0x36946091, 0x0E850F3D, 0x46B6BFC9, 0x7EA7D065, // [4][0xd8]
|
||||
0x13B6D5B0, 0x2BA7BA1C, 0x63940AE8, 0x5B856544, 0xF3F36B00, 0xCBE204AC, 0x83D1B458, 0xBBC0DBF4, // [4][0xe0]
|
||||
0x425B0AA5, 0x7A4A6509, 0x3279D5FD, 0x0A68BA51, 0xA21EB415, 0x9A0FDBB9, 0xD23C6B4D, 0xEA2D04E1, // [4][0xe8]
|
||||
0x873C0134, 0xBF2D6E98, 0xF71EDE6C, 0xCF0FB1C0, 0x6779BF84, 0x5F68D028, 0x175B60DC, 0x2F4A0F70, // [4][0xf0]
|
||||
0xCD796B76, 0xF56804DA, 0xBD5BB42E, 0x854ADB82, 0x2D3CD5C6, 0x152DBA6A, 0x5D1E0A9E, 0x650F6532, // [4][0xf8]
|
||||
0x081E60E7, 0x300F0F4B, 0x783CBFBF, 0x402DD013, 0xE85BDE57, 0xD04AB1FB, 0x9879010F, 0xA0686EA3 // [4][0x100]
|
||||
},
|
||||
{
|
||||
0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, // [5][0x08]
|
||||
0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, // [5][0x10]
|
||||
0xC00C303E, 0x2F3C5B27, 0x1B8090FD, 0xF4B0FBE4, 0x72F90749, 0x9DC96C50, 0xA975A78A, 0x4645CC93, // [5][0x18]
|
||||
0xA00A2821, 0x4F3A4338, 0x7B8688E2, 0x94B6E3FB, 0x12FF1F56, 0xFDCF744F, 0xC973BF95, 0x2643D48C, // [5][0x20]
|
||||
0x85F4168D, 0x6AC47D94, 0x5E78B64E, 0xB148DD57, 0x370121FA, 0xD8314AE3, 0xEC8D8139, 0x03BDEA20, // [5][0x28]
|
||||
0xE5F20E92, 0x0AC2658B, 0x3E7EAE51, 0xD14EC548, 0x570739E5, 0xB83752FC, 0x8C8B9926, 0x63BBF23F, // [5][0x30]
|
||||
0x45F826B3, 0xAAC84DAA, 0x9E748670, 0x7144ED69, 0xF70D11C4, 0x183D7ADD, 0x2C81B107, 0xC3B1DA1E, // [5][0x38]
|
||||
0x25FE3EAC, 0xCACE55B5, 0xFE729E6F, 0x1142F576, 0x970B09DB, 0x783B62C2, 0x4C87A918, 0xA3B7C201, // [5][0x40]
|
||||
0x0E045BEB, 0xE13430F2, 0xD588FB28, 0x3AB89031, 0xBCF16C9C, 0x53C10785, 0x677DCC5F, 0x884DA746, // [5][0x48]
|
||||
0x6E0243F4, 0x813228ED, 0xB58EE337, 0x5ABE882E, 0xDCF77483, 0x33C71F9A, 0x077BD440, 0xE84BBF59, // [5][0x50]
|
||||
0xCE086BD5, 0x213800CC, 0x1584CB16, 0xFAB4A00F, 0x7CFD5CA2, 0x93CD37BB, 0xA771FC61, 0x48419778, // [5][0x58]
|
||||
0xAE0E73CA, 0x413E18D3, 0x7582D309, 0x9AB2B810, 0x1CFB44BD, 0xF3CB2FA4, 0xC777E47E, 0x28478F67, // [5][0x60]
|
||||
0x8BF04D66, 0x64C0267F, 0x507CEDA5, 0xBF4C86BC, 0x39057A11, 0xD6351108, 0xE289DAD2, 0x0DB9B1CB, // [5][0x68]
|
||||
0xEBF65579, 0x04C63E60, 0x307AF5BA, 0xDF4A9EA3, 0x5903620E, 0xB6330917, 0x828FC2CD, 0x6DBFA9D4, // [5][0x70]
|
||||
0x4BFC7D58, 0xA4CC1641, 0x9070DD9B, 0x7F40B682, 0xF9094A2F, 0x16392136, 0x2285EAEC, 0xCDB581F5, // [5][0x78]
|
||||
0x2BFA6547, 0xC4CA0E5E, 0xF076C584, 0x1F46AE9D, 0x990F5230, 0x763F3929, 0x4283F2F3, 0xADB399EA, // [5][0x80]
|
||||
0x1C08B7D6, 0xF338DCCF, 0xC7841715, 0x28B47C0C, 0xAEFD80A1, 0x41CDEBB8, 0x75712062, 0x9A414B7B, // [5][0x88]
|
||||
0x7C0EAFC9, 0x933EC4D0, 0xA7820F0A, 0x48B26413, 0xCEFB98BE, 0x21CBF3A7, 0x1577387D, 0xFA475364, // [5][0x90]
|
||||
0xDC0487E8, 0x3334ECF1, 0x0788272B, 0xE8B84C32, 0x6EF1B09F, 0x81C1DB86, 0xB57D105C, 0x5A4D7B45, // [5][0x98]
|
||||
0xBC029FF7, 0x5332F4EE, 0x678E3F34, 0x88BE542D, 0x0EF7A880, 0xE1C7C399, 0xD57B0843, 0x3A4B635A, // [5][0xa0]
|
||||
0x99FCA15B, 0x76CCCA42, 0x42700198, 0xAD406A81, 0x2B09962C, 0xC439FD35, 0xF08536EF, 0x1FB55DF6, // [5][0xa8]
|
||||
0xF9FAB944, 0x16CAD25D, 0x22761987, 0xCD46729E, 0x4B0F8E33, 0xA43FE52A, 0x90832EF0, 0x7FB345E9, // [5][0xb0]
|
||||
0x59F09165, 0xB6C0FA7C, 0x827C31A6, 0x6D4C5ABF, 0xEB05A612, 0x0435CD0B, 0x308906D1, 0xDFB96DC8, // [5][0xb8]
|
||||
0x39F6897A, 0xD6C6E263, 0xE27A29B9, 0x0D4A42A0, 0x8B03BE0D, 0x6433D514, 0x508F1ECE, 0xBFBF75D7, // [5][0xc0]
|
||||
0x120CEC3D, 0xFD3C8724, 0xC9804CFE, 0x26B027E7, 0xA0F9DB4A, 0x4FC9B053, 0x7B757B89, 0x94451090, // [5][0xc8]
|
||||
0x720AF422, 0x9D3A9F3B, 0xA98654E1, 0x46B63FF8, 0xC0FFC355, 0x2FCFA84C, 0x1B736396, 0xF443088F, // [5][0xd0]
|
||||
0xD200DC03, 0x3D30B71A, 0x098C7CC0, 0xE6BC17D9, 0x60F5EB74, 0x8FC5806D, 0xBB794BB7, 0x544920AE, // [5][0xd8]
|
||||
0xB206C41C, 0x5D36AF05, 0x698A64DF, 0x86BA0FC6, 0x00F3F36B, 0xEFC39872, 0xDB7F53A8, 0x344F38B1, // [5][0xe0]
|
||||
0x97F8FAB0, 0x78C891A9, 0x4C745A73, 0xA344316A, 0x250DCDC7, 0xCA3DA6DE, 0xFE816D04, 0x11B1061D, // [5][0xe8]
|
||||
0xF7FEE2AF, 0x18CE89B6, 0x2C72426C, 0xC3422975, 0x450BD5D8, 0xAA3BBEC1, 0x9E87751B, 0x71B71E02, // [5][0xf0]
|
||||
0x57F4CA8E, 0xB8C4A197, 0x8C786A4D, 0x63480154, 0xE501FDF9, 0x0A3196E0, 0x3E8D5D3A, 0xD1BD3623, // [5][0xf8]
|
||||
0x37F2D291, 0xD8C2B988, 0xEC7E7252, 0x034E194B, 0x8507E5E6, 0x6A378EFF, 0x5E8B4525, 0xB1BB2E3C // [5][0x100]
|
||||
},
|
||||
{
|
||||
0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, // [6][0x08]
|
||||
0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, // [6][0x10]
|
||||
0x9C5BFAA6, 0xF458D66E, 0x4C5DA336, 0x245E8FFE, 0x39BB3F77, 0x51B813BF, 0xE9BD66E7, 0x81BE4A2F, // [6][0x18]
|
||||
0xD27607F5, 0xBA752B3D, 0x02705E65, 0x6A7372AD, 0x7796C224, 0x1F95EEEC, 0xA7909BB4, 0xCF93B77C, // [6][0x20]
|
||||
0x3D5B83BD, 0x5558AF75, 0xED5DDA2D, 0x855EF6E5, 0x98BB466C, 0xF0B86AA4, 0x48BD1FFC, 0x20BE3334, // [6][0x28]
|
||||
0x73767EEE, 0x1B755226, 0xA370277E, 0xCB730BB6, 0xD696BB3F, 0xBE9597F7, 0x0690E2AF, 0x6E93CE67, // [6][0x30]
|
||||
0xA100791B, 0xC90355D3, 0x7106208B, 0x19050C43, 0x04E0BCCA, 0x6CE39002, 0xD4E6E55A, 0xBCE5C992, // [6][0x38]
|
||||
0xEF2D8448, 0x872EA880, 0x3F2BDDD8, 0x5728F110, 0x4ACD4199, 0x22CE6D51, 0x9ACB1809, 0xF2C834C1, // [6][0x40]
|
||||
0x7AB7077A, 0x12B42BB2, 0xAAB15EEA, 0xC2B27222, 0xDF57C2AB, 0xB754EE63, 0x0F519B3B, 0x6752B7F3, // [6][0x48]
|
||||
0x349AFA29, 0x5C99D6E1, 0xE49CA3B9, 0x8C9F8F71, 0x917A3FF8, 0xF9791330, 0x417C6668, 0x297F4AA0, // [6][0x50]
|
||||
0xE6ECFDDC, 0x8EEFD114, 0x36EAA44C, 0x5EE98884, 0x430C380D, 0x2B0F14C5, 0x930A619D, 0xFB094D55, // [6][0x58]
|
||||
0xA8C1008F, 0xC0C22C47, 0x78C7591F, 0x10C475D7, 0x0D21C55E, 0x6522E996, 0xDD279CCE, 0xB524B006, // [6][0x60]
|
||||
0x47EC84C7, 0x2FEFA80F, 0x97EADD57, 0xFFE9F19F, 0xE20C4116, 0x8A0F6DDE, 0x320A1886, 0x5A09344E, // [6][0x68]
|
||||
0x09C17994, 0x61C2555C, 0xD9C72004, 0xB1C40CCC, 0xAC21BC45, 0xC422908D, 0x7C27E5D5, 0x1424C91D, // [6][0x70]
|
||||
0xDBB77E61, 0xB3B452A9, 0x0BB127F1, 0x63B20B39, 0x7E57BBB0, 0x16549778, 0xAE51E220, 0xC652CEE8, // [6][0x78]
|
||||
0x959A8332, 0xFD99AFFA, 0x459CDAA2, 0x2D9FF66A, 0x307A46E3, 0x58796A2B, 0xE07C1F73, 0x887F33BB, // [6][0x80]
|
||||
0xF56E0EF4, 0x9D6D223C, 0x25685764, 0x4D6B7BAC, 0x508ECB25, 0x388DE7ED, 0x808892B5, 0xE88BBE7D, // [6][0x88]
|
||||
0xBB43F3A7, 0xD340DF6F, 0x6B45AA37, 0x034686FF, 0x1EA33676, 0x76A01ABE, 0xCEA56FE6, 0xA6A6432E, // [6][0x90]
|
||||
0x6935F452, 0x0136D89A, 0xB933ADC2, 0xD130810A, 0xCCD53183, 0xA4D61D4B, 0x1CD36813, 0x74D044DB, // [6][0x98]
|
||||
0x27180901, 0x4F1B25C9, 0xF71E5091, 0x9F1D7C59, 0x82F8CCD0, 0xEAFBE018, 0x52FE9540, 0x3AFDB988, // [6][0xa0]
|
||||
0xC8358D49, 0xA036A181, 0x1833D4D9, 0x7030F811, 0x6DD54898, 0x05D66450, 0xBDD31108, 0xD5D03DC0, // [6][0xa8]
|
||||
0x8618701A, 0xEE1B5CD2, 0x561E298A, 0x3E1D0542, 0x23F8B5CB, 0x4BFB9903, 0xF3FEEC5B, 0x9BFDC093, // [6][0xb0]
|
||||
0x546E77EF, 0x3C6D5B27, 0x84682E7F, 0xEC6B02B7, 0xF18EB23E, 0x998D9EF6, 0x2188EBAE, 0x498BC766, // [6][0xb8]
|
||||
0x1A438ABC, 0x7240A674, 0xCA45D32C, 0xA246FFE4, 0xBFA34F6D, 0xD7A063A5, 0x6FA516FD, 0x07A63A35, // [6][0xc0]
|
||||
0x8FD9098E, 0xE7DA2546, 0x5FDF501E, 0x37DC7CD6, 0x2A39CC5F, 0x423AE097, 0xFA3F95CF, 0x923CB907, // [6][0xc8]
|
||||
0xC1F4F4DD, 0xA9F7D815, 0x11F2AD4D, 0x79F18185, 0x6414310C, 0x0C171DC4, 0xB412689C, 0xDC114454, // [6][0xd0]
|
||||
0x1382F328, 0x7B81DFE0, 0xC384AAB8, 0xAB878670, 0xB66236F9, 0xDE611A31, 0x66646F69, 0x0E6743A1, // [6][0xd8]
|
||||
0x5DAF0E7B, 0x35AC22B3, 0x8DA957EB, 0xE5AA7B23, 0xF84FCBAA, 0x904CE762, 0x2849923A, 0x404ABEF2, // [6][0xe0]
|
||||
0xB2828A33, 0xDA81A6FB, 0x6284D3A3, 0x0A87FF6B, 0x17624FE2, 0x7F61632A, 0xC7641672, 0xAF673ABA, // [6][0xe8]
|
||||
0xFCAF7760, 0x94AC5BA8, 0x2CA92EF0, 0x44AA0238, 0x594FB2B1, 0x314C9E79, 0x8949EB21, 0xE14AC7E9, // [6][0xf0]
|
||||
0x2ED97095, 0x46DA5C5D, 0xFEDF2905, 0x96DC05CD, 0x8B39B544, 0xE33A998C, 0x5B3FECD4, 0x333CC01C, // [6][0xf8]
|
||||
0x60F48DC6, 0x08F7A10E, 0xB0F2D456, 0xD8F1F89E, 0xC5144817, 0xAD1764DF, 0x15121187, 0x7D113D4F // [6][0x100]
|
||||
},
|
||||
{
|
||||
0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, // [7][0x08]
|
||||
0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, // [7][0x10]
|
||||
0x847609B4, 0xCD4A7493, 0x160EF3FA, 0x5F328EDD, 0xA56B8BD9, 0xEC57F6FE, 0x37137197, 0x7E2F0CB0, // [7][0x18]
|
||||
0xC64D0D6E, 0x8F717049, 0x5435F720, 0x1D098A07, 0xE7508F03, 0xAE6CF224, 0x7528754D, 0x3C14086A, // [7][0x20]
|
||||
0x0D006599, 0x443C18BE, 0x9F789FD7, 0xD644E2F0, 0x2C1DE7F4, 0x65219AD3, 0xBE651DBA, 0xF759609D, // [7][0x28]
|
||||
0x4F3B6143, 0x06071C64, 0xDD439B0D, 0x947FE62A, 0x6E26E32E, 0x271A9E09, 0xFC5E1960, 0xB5626447, // [7][0x30]
|
||||
0x89766C2D, 0xC04A110A, 0x1B0E9663, 0x5232EB44, 0xA86BEE40, 0xE1579367, 0x3A13140E, 0x732F6929, // [7][0x38]
|
||||
0xCB4D68F7, 0x827115D0, 0x593592B9, 0x1009EF9E, 0xEA50EA9A, 0xA36C97BD, 0x782810D4, 0x31146DF3, // [7][0x40]
|
||||
0x1A00CB32, 0x533CB615, 0x8878317C, 0xC1444C5B, 0x3B1D495F, 0x72213478, 0xA965B311, 0xE059CE36, // [7][0x48]
|
||||
0x583BCFE8, 0x1107B2CF, 0xCA4335A6, 0x837F4881, 0x79264D85, 0x301A30A2, 0xEB5EB7CB, 0xA262CAEC, // [7][0x50]
|
||||
0x9E76C286, 0xD74ABFA1, 0x0C0E38C8, 0x453245EF, 0xBF6B40EB, 0xF6573DCC, 0x2D13BAA5, 0x642FC782, // [7][0x58]
|
||||
0xDC4DC65C, 0x9571BB7B, 0x4E353C12, 0x07094135, 0xFD504431, 0xB46C3916, 0x6F28BE7F, 0x2614C358, // [7][0x60]
|
||||
0x1700AEAB, 0x5E3CD38C, 0x857854E5, 0xCC4429C2, 0x361D2CC6, 0x7F2151E1, 0xA465D688, 0xED59ABAF, // [7][0x68]
|
||||
0x553BAA71, 0x1C07D756, 0xC743503F, 0x8E7F2D18, 0x7426281C, 0x3D1A553B, 0xE65ED252, 0xAF62AF75, // [7][0x70]
|
||||
0x9376A71F, 0xDA4ADA38, 0x010E5D51, 0x48322076, 0xB26B2572, 0xFB575855, 0x2013DF3C, 0x692FA21B, // [7][0x78]
|
||||
0xD14DA3C5, 0x9871DEE2, 0x4335598B, 0x0A0924AC, 0xF05021A8, 0xB96C5C8F, 0x6228DBE6, 0x2B14A6C1, // [7][0x80]
|
||||
0x34019664, 0x7D3DEB43, 0xA6796C2A, 0xEF45110D, 0x151C1409, 0x5C20692E, 0x8764EE47, 0xCE589360, // [7][0x88]
|
||||
0x763A92BE, 0x3F06EF99, 0xE44268F0, 0xAD7E15D7, 0x572710D3, 0x1E1B6DF4, 0xC55FEA9D, 0x8C6397BA, // [7][0x90]
|
||||
0xB0779FD0, 0xF94BE2F7, 0x220F659E, 0x6B3318B9, 0x916A1DBD, 0xD856609A, 0x0312E7F3, 0x4A2E9AD4, // [7][0x98]
|
||||
0xF24C9B0A, 0xBB70E62D, 0x60346144, 0x29081C63, 0xD3511967, 0x9A6D6440, 0x4129E329, 0x08159E0E, // [7][0xa0]
|
||||
0x3901F3FD, 0x703D8EDA, 0xAB7909B3, 0xE2457494, 0x181C7190, 0x51200CB7, 0x8A648BDE, 0xC358F6F9, // [7][0xa8]
|
||||
0x7B3AF727, 0x32068A00, 0xE9420D69, 0xA07E704E, 0x5A27754A, 0x131B086D, 0xC85F8F04, 0x8163F223, // [7][0xb0]
|
||||
0xBD77FA49, 0xF44B876E, 0x2F0F0007, 0x66337D20, 0x9C6A7824, 0xD5560503, 0x0E12826A, 0x472EFF4D, // [7][0xb8]
|
||||
0xFF4CFE93, 0xB67083B4, 0x6D3404DD, 0x240879FA, 0xDE517CFE, 0x976D01D9, 0x4C2986B0, 0x0515FB97, // [7][0xc0]
|
||||
0x2E015D56, 0x673D2071, 0xBC79A718, 0xF545DA3F, 0x0F1CDF3B, 0x4620A21C, 0x9D642575, 0xD4585852, // [7][0xc8]
|
||||
0x6C3A598C, 0x250624AB, 0xFE42A3C2, 0xB77EDEE5, 0x4D27DBE1, 0x041BA6C6, 0xDF5F21AF, 0x96635C88, // [7][0xd0]
|
||||
0xAA7754E2, 0xE34B29C5, 0x380FAEAC, 0x7133D38B, 0x8B6AD68F, 0xC256ABA8, 0x19122CC1, 0x502E51E6, // [7][0xd8]
|
||||
0xE84C5038, 0xA1702D1F, 0x7A34AA76, 0x3308D751, 0xC951D255, 0x806DAF72, 0x5B29281B, 0x1215553C, // [7][0xe0]
|
||||
0x230138CF, 0x6A3D45E8, 0xB179C281, 0xF845BFA6, 0x021CBAA2, 0x4B20C785, 0x906440EC, 0xD9583DCB, // [7][0xe8]
|
||||
0x613A3C15, 0x28064132, 0xF342C65B, 0xBA7EBB7C, 0x4027BE78, 0x091BC35F, 0xD25F4436, 0x9B633911, // [7][0xf0]
|
||||
0xA777317B, 0xEE4B4C5C, 0x350FCB35, 0x7C33B612, 0x866AB316, 0xCF56CE31, 0x14124958, 0x5D2E347F, // [7][0xf8]
|
||||
0xE54C35A1, 0xAC704886, 0x7734CFEF, 0x3E08B2C8, 0xC451B7CC, 0x8D6DCAEB, 0x56294D82, 0x1F1530A5 // [7][0x100]
|
||||
}
|
||||
};
|
||||
|
||||
/* private (static) function factoring out byte-by-byte CRC computation using just one slice of the lookup table*/
|
||||
static uint32_t s_crc_generic_sb1(const uint8_t *input, int length, uint32_t crc, const uint32_t *table_ptr) {
|
||||
uint32_t(*table)[8][256] = (uint32_t(*)[8][256])table_ptr;
|
||||
while (length-- > 0) {
|
||||
crc = (crc >> 8) ^ (*table)[0][(crc & 0xff) ^ *input++];
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* The inner loops of the CRC functions that process large blocks of data work best when input is aligned*/
|
||||
/* This function begins processing input data one byte at a time until the input pointer is 4-byte aligned*/
|
||||
/* Advances the input pointer and reduces the length (both passed by reference)*/
|
||||
static inline uint32_t s_crc_generic_align(
|
||||
const uint8_t **input,
|
||||
int *length,
|
||||
uint32_t crc,
|
||||
const uint32_t *table_ptr) {
|
||||
|
||||
/* Get the 4-byte memory alignment of our input buffer by looking at the least significant 2 bits*/
|
||||
size_t input_alignment = ((size_t)*input) & 0x3;
|
||||
|
||||
/* Compute the number of input bytes that precede the first 4-byte aligned block (will be in range 0-3)*/
|
||||
size_t leading = (4 - input_alignment) & 0x3;
|
||||
|
||||
/* Determine what's left without the leading input bytes (might be negative)*/
|
||||
size_t remaining = *length - leading;
|
||||
|
||||
/* Process unaligned leading input bytes one at a time*/
|
||||
if (leading && remaining > 0) {
|
||||
crc = s_crc_generic_sb1(*input, (uint32_t)leading, crc, table_ptr);
|
||||
*input += leading;
|
||||
*length -= (int)leading;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* private (static) function to compute a generic slice-by-4 CRC using the specified lookup table (4 table slices)*/
|
||||
static uint32_t s_crc_generic_sb4(const uint8_t *input, int length, uint32_t crc, const uint32_t *table_ptr) {
|
||||
const uint32_t *current = (const uint32_t *)input;
|
||||
int remaining = length;
|
||||
uint32_t(*table)[8][256] = (uint32_t(*)[8][256])table_ptr;
|
||||
|
||||
while (remaining >= 4) {
|
||||
crc ^= *current++;
|
||||
crc = (*table)[3][crc & 0xff] ^ (*table)[2][(crc >> 8) & 0xff] ^ (*table)[1][(crc >> 16) & 0xff] ^
|
||||
(*table)[0][crc >> 24];
|
||||
remaining -= 4;
|
||||
}
|
||||
|
||||
return s_crc_generic_sb1(&input[length - remaining], remaining, crc, table_ptr);
|
||||
}
|
||||
|
||||
/* private (static) function to compute a generic slice-by-8 CRC using the specified lookup table (8 table slices)*/
|
||||
static uint32_t s_crc_generic_sb8(const uint8_t *input, int length, uint32_t crc, const uint32_t *table_ptr) {
|
||||
const uint32_t *current = (const uint32_t *)input;
|
||||
int remaining = length;
|
||||
uint32_t(*table)[8][256] = (uint32_t(*)[8][256])table_ptr;
|
||||
|
||||
while (remaining >= 8) {
|
||||
uint32_t c1 = *current++ ^ crc;
|
||||
uint32_t c2 = *current++;
|
||||
uint32_t t1 = (*table)[7][c1 & 0xff] ^ (*table)[6][(c1 >> 8) & 0xff] ^ (*table)[5][(c1 >> 16) & 0xff] ^
|
||||
(*table)[4][(c1 >> 24) & 0xff];
|
||||
uint32_t t2 = (*table)[3][c2 & 0xff] ^ (*table)[2][(c2 >> 8) & 0xff] ^ (*table)[1][(c2 >> 16) & 0xff] ^
|
||||
(*table)[0][(c2 >> 24) & 0xff];
|
||||
crc = t1 ^ t2;
|
||||
remaining -= 8;
|
||||
}
|
||||
return s_crc_generic_sb4(&input[length - remaining], remaining, crc, table_ptr);
|
||||
}
|
||||
|
||||
/* Computes the Castagnoli CRC32c (iSCSI) using one byte at a time, i.e. no slicing. */
|
||||
static uint32_t s_crc32c_no_slice(const uint8_t *input, int length, uint32_t previousCrc32c) {
|
||||
return ~s_crc_generic_sb1(input, length, ~previousCrc32c, &CRC32C_TABLE[0][0]);
|
||||
}
|
||||
|
||||
/* Computes the Castagnoli CRC32c (iSCSI) using slice-by-8. */
|
||||
static uint32_t s_crc32c_sb8(const uint8_t *input, int length, uint32_t previousCrc32) {
|
||||
uint32_t crc = s_crc_generic_align(&input, &length, ~previousCrc32, &CRC32C_TABLE[0][0]);
|
||||
return ~s_crc_generic_sb8(input, length, crc, &CRC32C_TABLE[0][0]);
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
*
|
||||
* Calculate CRC-32C (Castagnoli) for the specified input data.
|
||||
*
|
||||
* If the host is big endian the calculation is the byte-by-byte, aka,
|
||||
* slice-by-1, version. Otherwise the calculation utilizes the
|
||||
* slice-by-8 optimized calculation.
|
||||
*
|
||||
* Return the CRC value on success or 0 on error.
|
||||
************************************************************************/
|
||||
uint32_t
|
||||
ms_crc32c (const uint8_t* input, int length, uint32_t previousCRC32C)
|
||||
{
|
||||
if (!input || length <= 0)
|
||||
return 0;
|
||||
|
||||
if (ms_bigendianhost())
|
||||
return s_crc32c_no_slice(input, length, previousCRC32C);
|
||||
else
|
||||
return s_crc32c_sb8(input, length, previousCRC32C);
|
||||
} /* End of ms_crc32c() */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,196 @@
|
||||
<doxygenlayout version="1.0">
|
||||
<!-- Generated by doxygen 1.8.14 -->
|
||||
<!-- Navigation index tabs for HTML output -->
|
||||
<navindex>
|
||||
<tab type="mainpage" visible="yes" title="Home"/>
|
||||
<tab type="pages" visible="no" title="" intro=""/>
|
||||
<tab type="modules" visible="yes" title="Reference Documentation" intro=""/>
|
||||
<tab type="namespaces" visible="no" title="">
|
||||
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="classes" visible="no" title="">
|
||||
<tab type="classlist" visible="yes" title="" intro=""/>
|
||||
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||
<tab type="hierarchy" visible="yes" title="" intro=""/>
|
||||
<tab type="classmembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="files" visible="no" title="">
|
||||
<tab type="filelist" visible="no" title="" intro=""/>
|
||||
<tab type="globals" visible="no" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="globals" visible="yes" title="Functions, etc." intro=""/>
|
||||
<tab type="user" visible="yes" url="@ref page-examples" title="Examples" intro="library examples"/>
|
||||
<tab type="user" visible="yes" url="@ref page-faq" title="FAQ" intro="FAQ"/>
|
||||
</navindex>
|
||||
|
||||
<!-- Layout definition for a class page -->
|
||||
<class>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
|
||||
<memberdecl>
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<publicslots title=""/>
|
||||
<signals title=""/>
|
||||
<publicmethods title=""/>
|
||||
<publicstaticmethods title=""/>
|
||||
<publicattributes title=""/>
|
||||
<publicstaticattributes title=""/>
|
||||
<protectedtypes title=""/>
|
||||
<protectedslots title=""/>
|
||||
<protectedmethods title=""/>
|
||||
<protectedstaticmethods title=""/>
|
||||
<protectedattributes title=""/>
|
||||
<protectedstaticattributes title=""/>
|
||||
<packagetypes title=""/>
|
||||
<packagemethods title=""/>
|
||||
<packagestaticmethods title=""/>
|
||||
<packageattributes title=""/>
|
||||
<packagestaticattributes title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
<privatetypes title=""/>
|
||||
<privateslots title=""/>
|
||||
<privatemethods title=""/>
|
||||
<privatestaticmethods title=""/>
|
||||
<privateattributes title=""/>
|
||||
<privatestaticattributes title=""/>
|
||||
<friends title=""/>
|
||||
<related title="" subtitle=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<constructors title=""/>
|
||||
<functions title=""/>
|
||||
<related title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
</memberdef>
|
||||
<allmemberslink visible="yes"/>
|
||||
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||
<authorsection visible="yes"/>
|
||||
</class>
|
||||
|
||||
<!-- Layout definition for a namespace page -->
|
||||
<namespace>
|
||||
<briefdescription visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</namespace>
|
||||
|
||||
<!-- Layout definition for a file page -->
|
||||
<file>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<includegraph visible="$INCLUDE_GRAPH"/>
|
||||
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
|
||||
<sourcelink visible="yes"/>
|
||||
<memberdecl>
|
||||
<classes visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection/>
|
||||
</file>
|
||||
|
||||
<!-- Layout definition for a group page -->
|
||||
<group>
|
||||
<briefdescription visible="yes"/>
|
||||
<groupgraph visible="$GROUP_GRAPHS"/>
|
||||
<memberdecl>
|
||||
<nestedgroups visible="yes" title=""/>
|
||||
<dirs visible="yes" title=""/>
|
||||
<files visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</group>
|
||||
|
||||
<!-- Layout definition for a directory page -->
|
||||
<directory>
|
||||
<briefdescription visible="yes"/>
|
||||
<directorygraph visible="yes"/>
|
||||
<memberdecl>
|
||||
<dirs visible="yes"/>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
</directory>
|
||||
</doxygenlayout>
|
@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Documentation build directory, relative to script directory
|
||||
DOCDIR=gh-pages
|
||||
|
||||
# Extract version from header
|
||||
if [[ $(grep LIBMSEED_VERSION ../libmseed.h) =~ LIBMSEED_VERSION[[:space:]]+\"(.*)\"[[:space:]]* ]]; then
|
||||
PROJECT_VERSION=${BASH_REMATCH[1]}
|
||||
else
|
||||
echo "WARNING: Cannot extract version"
|
||||
fi
|
||||
|
||||
# Generate year and date strings
|
||||
CURRENT_YEAR=$(date -u +%Y)
|
||||
CURRENT_DATE=$(date -u +%Y-%m-%d)
|
||||
|
||||
# Check for command line options
|
||||
while getopts ":YNP" o; do
|
||||
case "${o}" in
|
||||
Y)
|
||||
PUSHYES=Y
|
||||
;;
|
||||
N)
|
||||
PUSHYES=N
|
||||
;;
|
||||
P)
|
||||
BUILDPDF=Y
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 [-Y] [-N] [-P]" 1>&2;
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
# Build extra options for injection into config
|
||||
DOXYGENCONFIG+="PROJECT_NUMBER=${PROJECT_VERSION}\n"
|
||||
DOXYGENCONFIG+="ALIASES+=currentyear='${CURRENT_YEAR}'\n"
|
||||
DOXYGENCONFIG+="ALIASES+=currentdate='${CURRENT_DATE}'\n"
|
||||
|
||||
if [[ "$BUILDPDF" == "Y" ]]; then
|
||||
DOXYGENCONFIG+="GENERATE_LATEX=YES\n"
|
||||
fi
|
||||
|
||||
# Documentation build command, injecting current project version
|
||||
DOCBUILD="(cat Doxyfile; echo -e '${DOXYGENCONFIG}') | doxygen -"
|
||||
|
||||
# Change to working directory, aka base directory of script
|
||||
BASEDIR=$(dirname $0)
|
||||
cd $BASEDIR || { echo "Cannot change-directory to $BASEDIR, exiting"; exit 1; }
|
||||
|
||||
# Make clean gh-pages directory
|
||||
rm -rf $DOCDIR
|
||||
mkdir $DOCDIR || { echo "Cannot create directory '$DOCDIR', exiting"; exit 1; }
|
||||
|
||||
# Build docs
|
||||
echo "Building docs"
|
||||
eval $DOCBUILD || { echo "Error running '$DOCBUILD', exiting"; exit 1; }
|
||||
|
||||
# Build PDF and copy to current directory
|
||||
if [[ "$BUILDPDF" == "Y" ]]; then
|
||||
if [[ -d latex ]]; then
|
||||
echo "Building PDF"
|
||||
BUILDPDF=$(cd latex; make pdf 2>&1)
|
||||
cp latex/refman.pdf libmseed.pdf
|
||||
else
|
||||
echo "WARNING: Cannot build PDF, no source latex directory"
|
||||
fi
|
||||
fi
|
||||
|
||||
GITREMOTE=$(git config --get remote.origin.url)
|
||||
|
||||
# Exit if already instructed to not push
|
||||
if [[ "$PUSHYES" == "N" ]]; then
|
||||
echo "Exiting without pushing to remote"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Unless pushing already acknowledged ask if docs should be pushed
|
||||
if [[ "$PUSHYES" != "Y" ]]; then
|
||||
read -p "Push documentation to gh-pages branch of $GITREMOTE (y/N)? " PUSHYES
|
||||
|
||||
if [[ "$PUSHYES" != "Y" && "$PUSHYES" != "y" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
cd $DOCDIR || { echo "Cannot change-directory to $DOCDIR, exiting"; exit 1; }
|
||||
|
||||
# Init repo, add & commit files, add remote origin
|
||||
git init
|
||||
touch .nojekyll
|
||||
git add .
|
||||
git commit -m 'committing documentation'
|
||||
|
||||
git remote add origin $GITREMOTE
|
||||
|
||||
echo "Pushing contents of $BASEDIR/$DOCDIR to $GITREMOTE branch gh-pages"
|
||||
git push --quiet --force origin main:gh-pages
|
@ -0,0 +1,78 @@
|
||||
/**
|
||||
@page page-capabilities Capabilities
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@section overview Overview
|
||||
|
||||
This section describes the capabilities and fundamentals of the
|
||||
library.
|
||||
|
||||
@subsection data-records Data Records
|
||||
|
||||
@note miniSEED data are constructed as records, typically anywhere
|
||||
from 128 to 4096 bytes in length. Each record is independent,
|
||||
identifying the data source, encoding type, etc. in header structures.
|
||||
Reconstructing a continuous time series from an arbitrary number of
|
||||
data records is an excersize for a format reader, e.g. this library.
|
||||
|
||||
A miniSEED record is represented in the library using the MS3Record
|
||||
structure. This structure is used for both unpacking and packing of
|
||||
miniSEED records. When unpacking with msr3_parse() this structure is
|
||||
populated. When packing with msr3_pack() this structure is used as a
|
||||
template for the resulting data records and as a source of samples to
|
||||
be packed.
|
||||
|
||||
@subsubsection Data Sample Encodings
|
||||
|
||||
The library supports all commonly used @ref encoding-values for
|
||||
decoding and a subset of the most common values for encoding. The
|
||||
following data encoding formats are supported for both unpacking and
|
||||
packing: ASCII, INT16, INT32, FLOAT32, FLOAT64, STEIM1 and STEIM2.
|
||||
The INT and FLOAT encodings each have two versions for quantities with
|
||||
a different number of bits of representation. The STEIM compression
|
||||
encodings work with 32-bit integers. The following data encoding
|
||||
formats are supported for unpacking only: GEOSCOPE (24-bit, 16/3 and
|
||||
16/4 gain ranged), CDSN, SRO and DWWSSN.
|
||||
|
||||
@subsection traces Traces
|
||||
|
||||
In order to reconstruct, manage and process continuous trace segments
|
||||
the library provides @ref trace-list functionality.
|
||||
|
||||
@ref trace-list structures are nested to contain an arbitrary number
|
||||
of identified time series, each containing an arbitrary number
|
||||
continuous time series segments, aka traces. While a trace list is
|
||||
normally used to hold trace information and associated data samples
|
||||
they can also be used without data samples as a means of tracking data
|
||||
coverage without actual sample values.
|
||||
|
||||
@subsection time-representation Time representation
|
||||
|
||||
Internally, time stamps are represented as nanoseconds since the
|
||||
Unix/POSIX epoch via the nstime_t data type. A number of functions
|
||||
exist to parse or generate date-time strings to or from this
|
||||
representation. See @ref time-related.
|
||||
|
||||
*Note:* nanosecond time resolution does not mean the data included
|
||||
this resolution.
|
||||
|
||||
@subsection time-series-data Time series data formats
|
||||
|
||||
Time series data samples are supported in a few different formats
|
||||
depending on how they are unpacked or will be packed. Samples can be
|
||||
either ASCII, 32-bit integer, 32-bit floats or 64-bit double precision
|
||||
floats. These types are represented internally using the
|
||||
single-character @ref sample-types.
|
||||
|
||||
@subsection log-messages Log messages
|
||||
|
||||
All of the log and diagnostic messages emitted by the library
|
||||
functions use a central logging facility. It is common for programs
|
||||
that use the library to also use these logging functions.
|
||||
Furthermore, the output from these logging interfaces can be
|
||||
controlled by directing output to callback functions. This is useful
|
||||
when the library will be embedded in a larger system with it's own
|
||||
logging facility. See the @ref logging page for more details.
|
||||
|
||||
*/
|
@ -0,0 +1,20 @@
|
||||
.memtitle {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
/* Replace content of permalinks */
|
||||
.permalink a {
|
||||
color: transparent;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.permalink a:before {
|
||||
content: url('https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/link.svg');
|
||||
visibility: hidden;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
/* Show link icon when member title is hovered */
|
||||
h2.memtitle:hover .permalink a:before {
|
||||
visibility: visible;
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/**
|
||||
@page page-examples Examples
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@section examples-overview Overview
|
||||
|
||||
The most basic usage of the library is illustrated in the @ref
|
||||
page-tutorial. This page contains full example programs that utilize
|
||||
the library for common tasks. These examples are included in the
|
||||
source distribution and (most) are used in the test suite.
|
||||
|
||||
While these are full working programs the aspects not related to
|
||||
library usage, e.g. argument parsing, are often minimized and left
|
||||
uncommented as they will change in real world usage.
|
||||
|
||||
@section example-mseedview Read miniSEED from files
|
||||
|
||||
A simple program to read miniSEED from files and print details from
|
||||
each record:
|
||||
|
||||
@include mseedview.c
|
||||
|
||||
@section example-lm_read_selection Reading with selections
|
||||
|
||||
Read miniSEED with @ref data-selections used to limit what is read.
|
||||
Additionally, this program reads data into a @ref trace-list and
|
||||
illustrates traversing the entries.
|
||||
|
||||
@include lm_read_selection.c
|
||||
|
||||
@section example-lm_read_recordlist Reading with record lists
|
||||
|
||||
Read miniSEED a file in 2 passes:
|
||||
-# Read the file and construct a @ref trace-list without unpacking the
|
||||
data samples and constructing a @ref record-list
|
||||
-# Unpack the data samples for each segment individually.
|
||||
|
||||
This pattern allows the caller to selectively unpack the data by
|
||||
segment if desired.
|
||||
|
||||
While this example unpacks the data into a buffer allocated by the
|
||||
library, the unpacking routine mstl3_unpack_recordlist() also allows
|
||||
data samples to be placed directly into caller-specified memory
|
||||
buffers.
|
||||
|
||||
While this example uses ms3_readtracelist() for reading data from a
|
||||
file, the same functionality exists in mstl3_readbuffer() for reading
|
||||
data from a memory buffer.
|
||||
|
||||
@include lm_read_recordlist.c
|
||||
|
||||
@section example-lm_read_buffer Reading from memory buffers
|
||||
|
||||
Read miniSEED from memory buffers. In this case a file is read into a
|
||||
buffer simply to illustrate reading from a buffer. In practice this
|
||||
would functionality would be used with data received via a network
|
||||
connection or some other, non-file, mechanism.
|
||||
|
||||
@include lm_read_buffer.c
|
||||
|
||||
@section example-lm_pararead Reading files in parallel
|
||||
|
||||
Read miniSEED in parallel using re-entrant interfaces and POSIX threading.
|
||||
|
||||
@include lm_pararead.c
|
||||
|
||||
@section example-lm_pack Writing miniSEED
|
||||
|
||||
An example of creating miniSEED. Static data with known signal is
|
||||
used for input for illustration and testing.
|
||||
|
||||
@include lm_pack.c
|
||||
|
||||
@section example-lm_pack_rollingbuffer Writing miniSEED with rolling buffer
|
||||
|
||||
An example of creating miniSEED using a ::MS3TraceList as a rolling
|
||||
buffer of data. This pattern is useful for generating miniSEED in a
|
||||
streaming fashion for scenarios where holding all data in memory is
|
||||
not possible or practical. For example, very large data sets or
|
||||
continuous, streaming data.
|
||||
|
||||
An input file of miniSEED is used as a convenient data source.
|
||||
::MS3Record containers can be constructed for any arbitrary data and
|
||||
follow the same pattern of record generation.
|
||||
|
||||
@include lm_pack_rollingbuffer.c
|
||||
|
||||
@section example-lm_sids Working with Source Identifiers
|
||||
|
||||
An example of mapping between source identifiers (SIDs) and SEED
|
||||
identifier codes.
|
||||
|
||||
@include lm_sids.c
|
||||
|
||||
*/
|
@ -0,0 +1,110 @@
|
||||
/**
|
||||
@page page-faq Frequency asked questions
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@section faq-list FAQs
|
||||
|
||||
@subsection faq-1 How do I read/write data from/to files?
|
||||
|
||||
The short answer is to use ms3_readmsr(), ms3_readtracelist(), and ms3_writemsr().
|
||||
You can find descriptions and code examples in the @ref page-tutorial and @ref page-examples sections.
|
||||
|
||||
@subsection faq-2 Can I read/write data from/to memory buffers?
|
||||
|
||||
Yes! Use msr3_parse() to read data from a memory buffer, and msr3_pack() to write data to a memory buffer.
|
||||
The msr3_pack() function accepts a callback function that is called when records are completed, from there
|
||||
the caller can do whatever is desired with the record.
|
||||
|
||||
@subsection faq-3 How do I read data from a URL?
|
||||
|
||||
The library includes support for reading from URLs using <a class="el" href="https://curl.se/libcurl/">libcurl</a>.
|
||||
To use this feature, the library must be compiled with **LIBMSEED_URL** defined, and the program must be
|
||||
linked with both this library and libcurl.
|
||||
|
||||
The stream/file reading functions in the library will automatically detect URLs versus local files
|
||||
and there is no need to do anything special to use this feature.
|
||||
|
||||
Specifics of the URL support can be configured with @ref ms3_url_useragent(), @ref ms3_url_userpassword(),
|
||||
and @ref ms3_url_addheader().
|
||||
|
||||
To disable TLS/SSL peer and host verification set the **LIBMSEED_SSL_NOVERIFY** environment variable.
|
||||
|
||||
@subsection faq-4 miniSEED is simple, why is a library needed?
|
||||
|
||||
Indeed, a major advantage of miniSEED is that it is relatively simple. In specific cases, reading
|
||||
and even writing of miniSEED can a implemented with very little code. However, there are many
|
||||
combinations possible in record construction, data encodings, record lengths, proper time determination,
|
||||
endianess, etc. which make the general case non-trivial. With 2 versions of the format that are not
|
||||
binary compatible, the general case becomes even more complex.
|
||||
|
||||
<em>Importantly</em>, the library handles the task of re-assembling continuous time series data from independent,
|
||||
and arbitrarily organized, miniSEED records. This "beyond miniSEED" support no small task, and is required
|
||||
for most use cases.
|
||||
|
||||
Furthermore, the library contains optimizations for handling large volumes and highly-multiplexed data,
|
||||
as well efficiently dealing with historical quirks and data problems.
|
||||
|
||||
@subsection faq-5 Can I use libmseed strictly with miniSEED version 2?
|
||||
|
||||
Yes. The library is backwards compatible with miniSEED version 2, and will automatically detect the
|
||||
version of data being read. Version 2 records can be created by setting the @ref MSF_PACKVER2 flag
|
||||
when calling the pack or write functions.
|
||||
|
||||
@subsection faq-6 I need to use separate FDSN identifiers of Network, Station, Location and Channel.
|
||||
|
||||
<em>and what is the deal with this new Source Identifier?</em>
|
||||
|
||||
In 2020 the FDSN approved the <a class="el" href="https://docs.fdsn.org/projects/source-identifiers">Source Identifier</a>
|
||||
specification to overcome the limitations of <a class="el" href="https://fdsn.org/pdf/SEEDManual_V2.4.pdf">SEED</a>
|
||||
network, station, location, and channel codes.
|
||||
In particular length limitations, instrument-type code depletion, and provide a standard way to combine them.
|
||||
This specification is a superset of SEED codes and is backwards compatible as long as the codes are short
|
||||
enough to fit into SEED limitations.
|
||||
|
||||
As of major version 3, the library adopted the FDSN Source Identifer, often abbreviated to \a SID, replacing
|
||||
the previous representation that was very similar.
|
||||
|
||||
You can use the @ref ms_sid2nslc() and @ref ms_nslc2sid() routines to convert between the two representations.
|
||||
|
||||
Except for potentially larger individual codes, the major difference in the two representations is the
|
||||
\a channel code. In the SEED specification this is a fixed 3-character code, while in the FDSN Source Identifier
|
||||
specification the channel is 3 codes separated by underscores, with each code potentially being larger than a
|
||||
single character. The library is agnostic to form of a channel representation, accepting either and converting
|
||||
between them whenever possible and appropriate.
|
||||
|
||||
@subsection faq-7 The library API changed! Why? How do I port my libmseed 2.x program to the 3.x API?
|
||||
|
||||
Starting with major version 3 of the library the internal data model was changed to be based on miniSEED format
|
||||
version 3. This relatively large structural change required API changes, and the opportunity was taken To
|
||||
improve the API in other ways.
|
||||
|
||||
See the @ref porting-guide.
|
||||
|
||||
@subsection faq-8 I'm using the library and would like to cite it. How do I do that?
|
||||
|
||||
A publication is planned and will be added here when available.
|
||||
|
||||
For now, please cite the GitHub repository: https://github.com/EarthScope/libmseed
|
||||
|
||||
Thank you!
|
||||
|
||||
@subsection faq-9 This library sucks. What can I do?
|
||||
|
||||
It won't be everyone's cup of tea. Some alternative libraries are:
|
||||
|
||||
P. Crotwell's <a class="el" href="https://www.seis.sc.edu/seisFile.html">SeisFile</a> - Java library with miniSEED support.
|
||||
|
||||
D. Neuhauser's <a class="el" href="https://www.ncedc.org/qug/software/ucb/">Qlib2</a> - C library with miniSEED support.
|
||||
|
||||
(happy to add more here, please let me know!)
|
||||
|
||||
@subsection faq-10 This library is great, but doesn't do something I need. What can I do? How can I contribute?
|
||||
|
||||
Contributions of ideas, problems reports, and code are welcome!
|
||||
|
||||
Please <a class="el" href="https://github.com/EarthScope/libmseed/issues">post issues</a> to the repository.
|
||||
|
||||
Code contributions are best submitted as <a class="el" href="https://github.com/EarthScope/libmseed/pulls">pull requests</a>.
|
||||
|
||||
*/
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,77 @@
|
||||
/**
|
||||
@mainpage libmseed Documentation
|
||||
|
||||
@section Overview
|
||||
|
||||
The miniSEED library provides a framework for manipulation of miniSEED
|
||||
records, a format commonly used for seismological time series and
|
||||
related data. The library includes the functionality to read and
|
||||
write data records, in addition to reconstructing time series from
|
||||
multiple records.
|
||||
|
||||
The library should work in Unix-like, Windows and potentially other
|
||||
environments.
|
||||
|
||||
@subsection main-tutorial Getting started
|
||||
|
||||
The @subpage page-tutorial contains an overview of basic usage and
|
||||
examples to get you going.
|
||||
|
||||
The @subpage page-capabilities page provides an overview the data format
|
||||
fundamentals and capabilities of the library.
|
||||
|
||||
@subsection main-downloding Downloading and installing
|
||||
|
||||
The <a class="el" href="https://github.com/earthscope/libmseed/releases">releases</a>
|
||||
area contains release versions.
|
||||
|
||||
For installation instructions see the
|
||||
<a class="el" href="https://github.com/earthscope/libmseed/tree/master/INSTALL.md">INSTALL</a>
|
||||
file.
|
||||
|
||||
@subsection develop-main Development and issues
|
||||
|
||||
Please report <a class="el" href="https://github.com/earthscope/libmseed/issues">issues</a>
|
||||
to the project.
|
||||
|
||||
If you would like to contribute to the project please file Pull Requests
|
||||
and/or create issues for discussion at the <a class="el" href="https://github.com/earthscope/libmseed/">
|
||||
libmseed project</a>.
|
||||
|
||||
@subsubsection porting-main Porting from earlier version of the library
|
||||
|
||||
A @ref porting-guide is available for developer porting software that
|
||||
previously used version 2 of the library.
|
||||
|
||||
@subsection versioning-main Versioning
|
||||
|
||||
Releases are versioned using <a class="el" href="http://semver.org/">Semantic Versioning</a>.
|
||||
|
||||
@subsection main-acknowledgements Acknowlegements
|
||||
|
||||
Numerous improvements have been incorporated based on feedback and
|
||||
patches submitted by others. Individual acknowlegements are included
|
||||
in the ChangeLog and/or commit messages. Contributions are welcome and greatly appreciated.
|
||||
|
||||
This library also uses code bits published in the public domain and
|
||||
acknowledgement is included in the code whenever possible.
|
||||
|
||||
@subsection main-license License
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this software except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
<a class="el" href="http://www.apache.org/licenses/LICENSE-2.0">
|
||||
http://www.apache.org/licenses/LICENSE-2.0</a>
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Copyright (C) @currentyear Chad Trabant, EarthScope Data Services
|
||||
|
||||
Documentation last generated @currentdate
|
||||
*/
|
@ -0,0 +1,179 @@
|
||||
/**
|
||||
@page porting-guide Guide for porting from earlier libmseed versions
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@section porting-overview Overview and approach
|
||||
|
||||
This page contains a description of major API changes from version 2
|
||||
to 3 of the library.
|
||||
|
||||
The recommended approach to porting is as follows:
|
||||
|
||||
-# Read through the @ref porting-important, changing anything
|
||||
in the calling program that is obvious.
|
||||
|
||||
-# Try compiling the target program with the new library and fix any
|
||||
identified problems.
|
||||
|
||||
-# Read @ref porting-other to understand other changes that may not be
|
||||
identified at compile time but may yet effect the program.
|
||||
|
||||
@subsection porting-important Most important changes that commonly need attention
|
||||
|
||||
- Convert \c MSRecord structure type usage to ::MS3Record, which has
|
||||
similar (but not the same) members.
|
||||
|
||||
- Convert \c MSTraceList, \c MSTraceID, and \c MSTraceSeg structure
|
||||
types usage to ::MS3TraceList, ::MS3TraceID, and ::MS3TraceSeg, which
|
||||
have similar (but not the same) members.
|
||||
|
||||
- Convert usage of MSTraceGroups to ::MS3TraceList. Legacy "Trace Groups"
|
||||
are no longer supported. The @ref page-examples page contains examples
|
||||
of using @ref trace-list functionality.
|
||||
|
||||
- MS3TraceList.numtraces renamed to ::MS3TraceList.numtraceids.
|
||||
|
||||
- The \c fpos and \c last arguments of ::ms3_readmsr(), ::ms3_readmsr_r(),
|
||||
and ::ms3_readmsr_selection() have been removed. The same capability is
|
||||
available using the re-entrant ('_r') functions with ::MS3FileParam (msfp)
|
||||
- Stream/file position of returned record is (msfp->streampos - msr->reclen)
|
||||
- Starting position of a read can be set at \c msfp->startoffset
|
||||
- The last record read is identified by the return value of ::MS_ENDOFFILE
|
||||
|
||||
- Convert all \c hptime_t typed variables to \c nstime_t type.
|
||||
@note the \c nstime_t type is a nanosecond epoch value, whereas the
|
||||
previous \c hptime_t was a microsecond epoch value. Careful review is
|
||||
required for values used by a program directly (they really _should
|
||||
not_ be).
|
||||
|
||||
- Review and change functions with \c hptime in the name to their
|
||||
closest equivalent for the new \c nstime version. See @ref time-related.
|
||||
|
||||
- Change all usage of \c ms_hptime2isotimestr(), \c ms_hptime2mdtimestr(),
|
||||
and \c ms_hptime2seedtimestr() functions to use ms_nstime2timestr(), which
|
||||
has enumerated flags to specify the time string format. In general:
|
||||
- ms_hptime2isotimestr() becomes ms_nstime2timestr(nstime, timestr, ISOMONTHDAY, subsecond)
|
||||
- ms_hptime2mdtimestr() becomes ms_nstime2timestr(nstime, timestr, ISOMONTHDAY_SPACE, subsecond)
|
||||
- ms_hptime2seedtimestr() becomes ms_nstime2timestr(nstime, timestr, SEEDORDINAL, subsecond)
|
||||
|
||||
- The _time format_ and _subseconds_ flags have changed from integers
|
||||
to \c enum values, review and change calling of \c
|
||||
ms_nstime2timestr(), \c mstl3_printtracelist(), \c
|
||||
mstl3_printsynclist(), and \c mstl3_printgaplist().
|
||||
@note If the above functions are simply renamed and the flag values
|
||||
are not changed to use the enumerated types, leaving integers as
|
||||
arguments, there may be a **non-obvious bug**. Most compilers will
|
||||
quiety accept an integer for the enum argument, which may or may not
|
||||
match the desired time format or subsecond handling. Assume _not_.
|
||||
|
||||
- Adapt to new identification of a record source. The channel
|
||||
identification has changed from \c NN_SSS_LL_CHA, commonly printed in
|
||||
library console output and logging, to a URI-style Source Identifier
|
||||
(SID) with the pattern \c FDSN:NN_SSS_LL_B_S_s. The following helper
|
||||
functions are available for mapping between the new URI-based scheme
|
||||
and the traditional SEED network, station, location, channel scheme:
|
||||
- ms_sid2nslc(): convert SID to traditional SEED identifiers
|
||||
- ms_nslc2sid(): convert traditional SEED identifiers to an SID
|
||||
- ms_seedchan2xchan(): convert SEED channel to SID-style channel components
|
||||
- ms_xchan2seedchan(): convert SID band, source and position to SEED channel
|
||||
|
||||
- The new data model allows sampling rate to be specified in samples/second
|
||||
(Hertz) or sampling period (seconds). This is represented in the \a
|
||||
samprate values, such as ::MS3Record.samprate, as follows:
|
||||
- \c samprate >= 0.0 is a rate in samples/second (Hertz)
|
||||
- \c samprate < 0.0 is a (negated) sampling period in seconds
|
||||
|
||||
It is common that rates equal to or greater than 1 Hz are represented
|
||||
in samples/second and rates less than 1 Hz are represented as a
|
||||
period.
|
||||
|
||||
Applications that must consistently have access to the samples/second
|
||||
representation may use the msr3_sampratehz() function.
|
||||
|
||||
@subsection porting-other Other changes that may need attention
|
||||
|
||||
- The supported range for the internal time scale is reduced from year
|
||||
5000 to year 2262 (due to the change in time resolution). If an
|
||||
application previously used the library with years beyond 2262, such
|
||||
programs should be adapted for this new limit.
|
||||
|
||||
- The \c off_t type is no longer used by the library due to
|
||||
non-portable, inconsistent size. Instead, the \c int64_t type is
|
||||
used. Calling programs should adjust their usage accordingly. The
|
||||
API changed as follows:
|
||||
- The global LM_SIZEOF_OFF_T is removed, no longer needed
|
||||
- The type of \a fpos (file position) arument of ms3_readmsr(), ms3_readmsr_r(), and ms3_readmsr_selection() has changed
|
||||
- Some internal functions and structures rarely used by callers were changed
|
||||
|
||||
- The \c flag typedef is now legacy, you may wish to convert to directly using int8_t
|
||||
|
||||
- The time and sample rate tolerances, specified as \c timetol and
|
||||
\c sampratetol arguments, have been replaced with ::MS3Tolerance which
|
||||
identifies callback functions that return tolerances for a specified ::MS3Record.
|
||||
|
||||
- The SEED 2.x data quality identifiers no longer exist in the new data model.
|
||||
The library maps these values to integer publications versions as follows:
|
||||
- Quality \b R => \b 1
|
||||
- Quality \b D => \b 2
|
||||
- Quality \b Q => \b 3
|
||||
- Quality \b M => \b 4
|
||||
- Unknown quality => \b 0
|
||||
|
||||
- For applications that need access to flags in the miniSEED 2.x fixed
|
||||
header, they have moved to the following locations:
|
||||
- Activity flags (field 12):
|
||||
- Bit 0 (calibration signals present) => Fixed header flags, bit 0
|
||||
- Bit 1 (time correction applied), not retained
|
||||
- Bit 2 (begining of event) => Extra header FDSN.Event.Begin
|
||||
- Bit 3 (end of event) => Extra header FDSN.Event.End
|
||||
- Bit 4 (positive leap second included) => Extra header FDSN.Time.LeapSecond
|
||||
- Bit 5 (negative leap second included) => Extra header FDSN.Time.LeapSecond
|
||||
- Bit 6 (event in progress) => Extra header FDSN.Event.InProgress
|
||||
- I/O flags (field 13):
|
||||
- Bit 0 (Station volume parity error) => Extra header FDSN.Flags.StationVolumeParityError
|
||||
- Bit 1 (Long record read) => Extra header FDSN.Flags.LongRecordRead
|
||||
- Bit 2 (Short record read) => Extra header FDSN.Flags.ShortRecordRead
|
||||
- Bit 3 (Start of time series) => Extra header FDSN.Flags.StartOfTimeSeries
|
||||
- Bit 4 (End of time series) => Extra header FDSN.Flags.EndOfTimeSeries
|
||||
- Bit 5 (Clock locked) => Fixed header flags, bit 2
|
||||
- Data quality flags (field 14):
|
||||
- Bit 0 (Amplifier saturation detected) => Extra header FDSN.Flags.AmplifierSaturation
|
||||
- Bit 1 (Digitizer clipping detected) => Extra header FDSN.Flags.DigitizerClipping
|
||||
- Bit 2 (Spikes detected) => Extra header FDSN.Flags.Spikes
|
||||
- Bit 3 (Glitches detected) => Extra header FDSN.Flags.Glitches
|
||||
- Bit 4 (Missing/padded data present) => Extra header FDSN.Flags.MissingData
|
||||
- Bit 5 (Telemetry synchronization error) => Extra header FDSN.Flags.TelemetrySyncError
|
||||
- Bit 6 (Digital filter may be charging) => Extra header FDSN.Flags.FilterCharging
|
||||
- Bit 7 (Time tag questionable) => Fixed header flags, bit 1
|
||||
|
||||
The existence of these boolean extra header values can be tested with mseh_exists().
|
||||
|
||||
@subsection porting-data-model-change Ramifications for change in data model
|
||||
|
||||
With an internal change in the data model, from miniSEED 2 to
|
||||
version 3, results in the following consequences:
|
||||
|
||||
- Version 2.x data quality indicators (D, R, Q and M) are no longer
|
||||
supported. These are mapped to version 3 publication versions.
|
||||
|
||||
- Version 2.x beam blockettes (400 & 405) are no longer supported,
|
||||
they will be dropped if reading records that contain such
|
||||
blockettes.
|
||||
|
||||
- Version 2.x opaque blockettes (2000) are no longer supported, they
|
||||
will be dropped if reading records that contain such blockettes.
|
||||
Note that the format version 3 @ref extra-headers functionality can
|
||||
be used to contain most arbitrary data.
|
||||
|
||||
- Version 2.x timing blockettes (500) contain one "Clock Model"
|
||||
designation per blockette, potentially allowing for multiple
|
||||
designations in a single record. Upon reading such a record, only
|
||||
the last clock model is retained (in the \c FDSN.Clock.Model @ref
|
||||
extra-headers).
|
||||
|
||||
- Version 2.x sequence numbers, as six digit ASCII string, are not
|
||||
retained. In the new format these values may be placed in @ref
|
||||
extra-headers by a calling program as desired.
|
||||
|
||||
*/
|
@ -0,0 +1,191 @@
|
||||
/**
|
||||
@page page-tutorial Tutorial
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@section common-usage Common usage
|
||||
|
||||
This page contains a description of basic library usage for the most
|
||||
common usage cases.
|
||||
|
||||
Additionally, the @ref page-examples page contains full examples for
|
||||
common use cases, which are also included in the 'examples' directory
|
||||
of the source code distribution.
|
||||
|
||||
@subsection reading Reading miniSEED data
|
||||
|
||||
A common task is to read a file of miniSEED records and perform some
|
||||
action based on the header values or apply some process to the data
|
||||
samples. There are two patterns to support this in the library, one
|
||||
to iterate over the file record-by-record and another to read all data
|
||||
into a collection of continuous series.
|
||||
|
||||
@subsubsection reading-records Reading miniSEED records from files
|
||||
|
||||
The ms3_readmsr() routine will open a specified file and return
|
||||
MS3Record structures for each miniSEED record it reads from the file.
|
||||
Called iteratively in a loop, all records are returned in the order
|
||||
discovered.
|
||||
|
||||
A code snippet for reading miniSEED from a file record-by-record:
|
||||
@anchor msr3-readmsr-snippet
|
||||
@code
|
||||
int main ()
|
||||
{
|
||||
char *filename = "datafile.mseed";
|
||||
MS3Record *msr = NULL;
|
||||
uint32_t flags = MSF_SKIPNOTDATA & MSF_UNPACKDATA;
|
||||
int verbose = 0;
|
||||
int retcode;
|
||||
|
||||
while ((retcode = ms3_readmsr (&msr, filename, flags, verbose)) == MS_NOERROR)
|
||||
{
|
||||
/* Do something with the record here, e.g. print */
|
||||
msr3_print (msr, verbose);
|
||||
}
|
||||
|
||||
if (retcode != MS_ENDOFFILE)
|
||||
ms_log (2, "Cannot read %s: %s\n", filename, ms_errorstr (retcode));
|
||||
|
||||
/* Cleanup memory and close file */
|
||||
ms3_readmsr (&msr, NULL, flags, verbose);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
|
||||
It is important to call ms3_readmsr() for cleanup as illustrated to
|
||||
free memory and close files.
|
||||
|
||||
There are more advanced versions of this routine. The ms3_readmsr_r()
|
||||
function is a thread-safe version that can be used in threaded
|
||||
programs to read files in parallel. The ms3_readmsr_selection()
|
||||
function is a thread-safe version that can additionally accept @ref
|
||||
data-selections to efficiently return only selected data.
|
||||
|
||||
@subsubsection reading-tracelists Reading miniSEED from files into traces lists
|
||||
|
||||
Another option is to read all miniSEED into a @ref trace-list without
|
||||
any handling of records. This is done with ms3_readtraces(), which is
|
||||
very useful for quickly reading data for processing. The data are
|
||||
returned in ordered, continuous segments ready for processing.
|
||||
|
||||
A code snippet for reading miniSEED from a file into a @ref trace-list :
|
||||
@anchor msr3-readtracelist-snippet
|
||||
@code
|
||||
int main ()
|
||||
{
|
||||
char *filename1 = "datafile1.mseed";
|
||||
char *filename2 = "datafile2.mseed";
|
||||
MS3TraceList *mstl = NULL;
|
||||
MS3Tolerance tol = MS3Tolerance_INITIALIZER;
|
||||
uint32_t flags = MSF_SKIPNOTDATA & MSF_UNPACKDATA;
|
||||
int verbose = 0;
|
||||
int retcode;
|
||||
|
||||
retcode = ms3_readtracelist (&mstl, filename1, &tol, 0, flags, verbose);
|
||||
|
||||
if (retcode != MS_NOERROR)
|
||||
ms_log (2, "Cannot read %s: %s\n", filename1, ms_errorstr (retcode));
|
||||
|
||||
retcode = ms3_readtracelist (&mstl, filename2, &tol, 0, flags, verbose);
|
||||
|
||||
if (retcode != MS_NOERROR)
|
||||
ms_log (2, "Cannot read %s: %s\n", filename2, ms_errorstr (retcode));
|
||||
|
||||
if (!mstl)
|
||||
{
|
||||
fprintf (stderr, "Error reading file\\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Do something with the traces here, e.g. print */
|
||||
mstl3_printtracelist (mstl, 0, verbose, 0, 0);
|
||||
|
||||
mstl3_free (&mstl, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
|
||||
There are more advanced versions of this routine. The
|
||||
ms3_readtracelist_timewin() function allows data to be limited to a
|
||||
specific time range while reading. The ms3_readtracelist_selection()
|
||||
can additionally accept @ref data-selections to efficiently return
|
||||
only selected data.
|
||||
|
||||
@subsubsection reading-buffers Reading miniSEED from memory
|
||||
|
||||
If an application is not designed to read miniSEED from files the
|
||||
library provides functions functionality to read data from memory.
|
||||
The mstl3_readbuffer() function will read all data from a buffer into
|
||||
a @ref trace-list. The low-level functions ms3_detect() and
|
||||
msr3_parse() can be used to detect and parse miniSEED records in
|
||||
memory buffers.
|
||||
|
||||
@subsection writing Writing miniSEED records
|
||||
|
||||
Another common task is to create miniSEED records. There are two
|
||||
patterns to support this in the library: one is to write data from
|
||||
library containers to files and another to create records and provide
|
||||
them back to the caller in a memory buffer via a callback function.
|
||||
|
||||
@subsubsection callback Callback design
|
||||
|
||||
If not writing directly to files, the packing interfaces use a
|
||||
callback design, where the caller specifies a function that will be
|
||||
called for every record that is created. It is the responsibility of
|
||||
the callback function to handle the record before returning. This
|
||||
design allows a program to do whatever is needed with generated
|
||||
miniSEED, i.e. write to files, send over the network, or even
|
||||
injection of more information.
|
||||
|
||||
@subsubsection writing-files Writing miniSEED data to files
|
||||
|
||||
The library supports writing miniSEED directly to files from either
|
||||
MS3Record or MS3TraceList containers using msr3_writemseed() or
|
||||
mstl3_writemseed() respectively.
|
||||
|
||||
A code snippet for writing miniSEED to a file from an MS3Record using msr3_writemseed():
|
||||
@anchor msr3-writemseed-snippet
|
||||
@code
|
||||
int main()
|
||||
{
|
||||
int packedrecords;
|
||||
int verbose = 0;
|
||||
char *msfile = "output.mseed";
|
||||
int32_t datasamples[] = {0,1,2,3,4,5,6,7,8,9,10};
|
||||
MS3Record *msr;
|
||||
|
||||
msr = msr3_init (NULL);
|
||||
|
||||
/* Populate MS3Record values */
|
||||
strcpy (msr->sid, "XX_TEXT__B_H_E");
|
||||
msr->formatversion = 3;
|
||||
msr->reclen = 512;
|
||||
msr->encoding = DE_STEIM2;
|
||||
msr->starttime = ms_timestr2nstime ("2018-12-01T00:00:00.000000000");
|
||||
msr->samprate = 20.0;
|
||||
|
||||
msr->datasamples = datasamples; /* pointer to 32-bit integer data samples */
|
||||
msr->numsamples = 11;
|
||||
msr->sampletype = 'i'; /* declare data type to be 32-bit integers */
|
||||
|
||||
/* Write all data in MS3Record to output file, using MSF_FLUSHDATA flag */
|
||||
packedrecords = msr3_writemseed (msr, msfile, 1, MSF_FLUSHDATA, verbose);
|
||||
|
||||
ms_log (0, "Wrote %d records to %s\n", packedrecords, msfile);
|
||||
|
||||
/* Disconnect datasamples pointer, otherwise msr3_free() will attempt to free() it */
|
||||
msr->datasamples = NULL;
|
||||
|
||||
msr3_free (&msr);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@subsubsection creating-records Creating miniSEED records
|
||||
|
||||
Records can be generated from data in either MS3Record or MS3TraceList
|
||||
containers using, respectively, msr3_pack() or and mstl3_pack().
|
||||
|
||||
*/
|
@ -0,0 +1,49 @@
|
||||
|
||||
# Build environment can be configured the following
|
||||
# environment variables:
|
||||
# CC : Specify the C compiler to use
|
||||
# CFLAGS : Specify compiler options to use
|
||||
|
||||
# Automatically configure URL support if libcurl is present
|
||||
# Test for curl-config command and add build options if so
|
||||
ifneq (,$(shell command -v curl-config))
|
||||
export LM_CURL_VERSION=$(shell curl-config --version)
|
||||
export CFLAGS:=$(CFLAGS) -DLIBMSEED_URL
|
||||
export LDFLAGS:=$(LDFLAGS) $(shell curl-config --libs)
|
||||
endif
|
||||
|
||||
# Required compiler parameters
|
||||
CFLAGS += -I..
|
||||
|
||||
LDFLAGS += -L..
|
||||
LDLIBS := -lmseed $(LDLIBS)
|
||||
|
||||
# Build all *.c source as independent programs
|
||||
SRCS := $(sort $(wildcard *.c))
|
||||
BINS := $(SRCS:%.c=%)
|
||||
|
||||
.PHONY: all
|
||||
.NOTPARALLEL: all
|
||||
all: libmseed $(BINS)
|
||||
|
||||
.PHONY: libmseed
|
||||
libmseed:
|
||||
@if [ ! -z "$(LM_CURL_VERSION)" ]; then \
|
||||
echo "Configured with $(LM_CURL_VERSION)"; \
|
||||
fi
|
||||
$(MAKE) -C .. $(MAKECMDGOALS)
|
||||
|
||||
# Build programs and check for executable
|
||||
$(BINS) : % : %.c
|
||||
@printf 'Building $<\n';
|
||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf *.o $(BINS) *.dSYM
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
@echo
|
||||
@echo "No install target, copy the executable(s) as needed"
|
||||
@echo
|
@ -0,0 +1,28 @@
|
||||
#
|
||||
# Nmake file for libmseed examples - MS Visual C/C++
|
||||
# Use 'nmake -f Makefile.win'
|
||||
|
||||
INCS = /I..
|
||||
LIBS = ../libmseed.lib
|
||||
OPTS = /O2 /D_CRT_SECURE_NO_WARNINGS
|
||||
|
||||
SRCS = lm_pack.c \
|
||||
lm_pack_rollingbuffer.c \
|
||||
lm_parse.c \
|
||||
lm_read_buffer.c \
|
||||
lm_read_recordlist.c \
|
||||
lm_read_selection.c \
|
||||
lm_sids.c \
|
||||
lm_timestr.c \
|
||||
mseedview.c
|
||||
|
||||
BINS = $(SRCS:.c=.exe)
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
.c.exe:
|
||||
$(CC) /nologo $(CFLAGS) $(INCS) $(OPTS) $(LIBS) $<
|
||||
|
||||
# Clean-up directives
|
||||
clean:
|
||||
-del *.obj *.exe *% *~
|
@ -0,0 +1,8 @@
|
||||
|
||||
Documentation of the libmseed interfaces can be found in the 'doc'
|
||||
directory.
|
||||
|
||||
Unix: the Makefile should work for most systems, try 'make'.
|
||||
|
||||
Win32: the Makefile.win is for Microsoft's nmake, try
|
||||
'nmake -f Makefile.win'
|
@ -0,0 +1,353 @@
|
||||
/***************************************************************************
|
||||
* A program for libmseed packing tests.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <libmseed.h>
|
||||
|
||||
#define VERSION "[libmseed " LIBMSEED_VERSION " example]"
|
||||
#define PACKAGE "lm_pack"
|
||||
|
||||
static flag verbose = 0;
|
||||
static int reclen = -1;
|
||||
static int encoding = 10;
|
||||
static int msformat = 3;
|
||||
static char *outfile = NULL;
|
||||
|
||||
static int parameter_proc (int argcount, char **argvec);
|
||||
static void usage (void);
|
||||
|
||||
/****************************************************************************
|
||||
* An expanding sinusoid of 500 samples.
|
||||
*
|
||||
* When truncated to integers:
|
||||
* - Signed differences in samples needing all bit lengths 3-31s.
|
||||
* - ONLY the last difference requires 31 bits, all others are <= 30
|
||||
* - Contain sequences of differences matching all Steim 1 and 2 encoding possibilities
|
||||
*
|
||||
* Values 1 through up to 220 do not require more than 16-bits.
|
||||
***************************************************************************/
|
||||
#define SINE_DATA_SAMPLES 500
|
||||
static float fsinedata[SINE_DATA_SAMPLES] =
|
||||
{0.000000,6.109208,10.246826,10.609957,6.764728,-0.075704,-7.409461,-12.346208,
|
||||
-12.731430,-8.062958,0.182060,8.985442,14.875067,15.276420,9.609196,-0.328370,
|
||||
-10.895428,-17.921131,-18.329336,-11.450576,0.526448,13.209973,21.590023,21.991385,
|
||||
13.643140,-0.791247,-16.014492,-26.008907,-26.383901,-16.253504,1.141655,19.412378,
|
||||
31.330871,31.652348,19.360848,-1.601465,-23.528777,-37.740204,-37.971107,-23.059260,
|
||||
2.200591,28.515156,45.458753,45.549217,27.460529,-2.976569,-34.554817,-54.753559,
|
||||
-54.637244,-32.697448,3.976416,41.869576,65.946052,65.535525,38.927729,-5.258928,
|
||||
-50.727832,-79.423116,-78.604029,-46.338644,6.897516,61.454325,95.650397,94.274177,
|
||||
55.152523,-8.983716,-74.441929,-115.188314,-113.063003,-65.633259,11.631511,
|
||||
90.165916,138.711322,135.590105,78.094013,-14.982665,-109.201193,-167.031082,
|
||||
-162.597954,-92.906331,19.213290,132.243134,201.124338,194.976222,110.510935,
|
||||
-24.541940,-160.132765,-242.166440,-233.790899,-131.430478,31.239561,193.887193,
|
||||
291.571675,280.319178,156.284630,-39.641741,-234.736391,-351.041770,-336.091216,
|
||||
-185.807912,50.163757,284.167632,422.624233,402.940140,220.870763,-63.319072,
|
||||
-343.979194,-508.782510,-483.061913,-262.504429,79.742042,416.345244,612.480366,
|
||||
579.087014,311.930343,-100.215795,-503.894220,-737.283353,-694.166245,-370.594813,
|
||||
125.706429,609.803540,887.480834,832.073438,440.209940,-157.404955,-737.913996,
|
||||
-1068.232708,-997.328409,-522.801872,196.778712,892.867950,1285.745847,1195.344115,
|
||||
620.767701,-245.634371,-1080.276240,-1547.486227,-1432.602775,-736.942489,
|
||||
306.195102,1306.919790,1862.433994,1716.866654,874.678227,-381.195062,-1580.993078,
|
||||
-2241.390126,-2057.430298,-1037.936774,473.995052,1912.398180,2697.345105,2465.422369,
|
||||
1231.399220,-588.724017,-2313.099844,-3245.922143,-2954.166800,-1460.594493,
|
||||
730.452133,2797.554253,3905.910007,3539.614901,1732.050527,-905.402443,-3383.226729,
|
||||
-4699.903513,-4240.862333,-2053.471832,1121.209554,4091.216806,5655.073452,
|
||||
5080.767553,2433.947965,-1387.235765,-4947.012887,-6804.092030,-6086.691631,
|
||||
-2884.198121,1714.957253,5981.403297,8186.245216,7291.383170,3416.857907,-2118.435721,
|
||||
-7231.576094,-9848.769674,-8734.036728,-4046.815355,2614.894255,8742.446660,
|
||||
11848.459577,10461.558685,4791.604321,-3225.420222,-10568.260176,-14253.597692,
|
||||
-12530.081077,-5671.864737,3975.823020,12774.525771,17146.276092,15006.771888,
|
||||
6711.880612,-4897.680529,-15440.350897,-20625.184991,-17971.999652,-7940.208402,
|
||||
6029.615451,18661.258563,24808.964001,21521.921578,9390.410233,-7418.851697,
|
||||
-22552.587165,-29840.229074,-25771.577789,-11101.908663,9123.111793,27253.593143,
|
||||
35890.411153,30858.590420,13120.982075,-11212.929535,-32932.401520,-43165.569941,
|
||||
-36947.585456,-15501.922592,13774.468128,39791.979238,51913.378983,44235.478131,
|
||||
18308.381438,-16912.953578,-48077.342225,-62431.517747,-52957.790070,-21614.930138,
|
||||
20756.856764,58084.250586,75077.753677,63396.198979,25508.869716,-25462.986446,
|
||||
-70169.698634,-90282.054065,-75887.560674,-30092.324242,31222.690356,84764.569627,
|
||||
108561.135815,90834.689747,35484.659605,-38269.404043,-102388.901147,-130535.943080,
|
||||
-108719.240618,-41825.273267,46887.838631,123670.298781,156952.641109,130117.096987,
|
||||
49276.805933,-57425.161274,-149366.146307,-188707.832667,-155716.756615,-58028.831480,
|
||||
70304.598043,180390.393831,226878.845103,186341.292651,68302.086980,-86041.981200,
|
||||
-217845.865904,-272760.106197,-222974.585037,-80353.310040,105265.874749,
|
||||
263063.225186,327906.831053,266792.649626,94480.755768,-128742.047924,-317647.960457,
|
||||
-394187.487304,-319201.052420,-111030.470003,157403.231090,383537.048821,
|
||||
473846.799900,381879.586964,130403.398591,-192385.288422,-463067.280664,
|
||||
-569581.409624,-456835.620147,-153063.413757,235071.184227,559057.643966,
|
||||
684630.722900,546467.782541,179546.337116,-287144.413901,-674908.656359,-822885.998573,
|
||||
-653642.002301,-210470.033463,350653.927224,814722.125712,989021.327043,781782.266485,
|
||||
246545.638548,-428093.004245,-983445.533844,-1188650.888674,-934978.952245,
|
||||
-288589.965744,522495.068481,1187046.097893,1428517.756157,1118118.116795,
|
||||
337539.108116,-637550.058001,-1432720.599829,-1716720.558561,-1337035.786123,
|
||||
-394463.210730,777745.745791,1729148.322568,2062985.588205,1598702.057951,
|
||||
460582.328770,-948539.335064,-2086795.934450,-2478993.447111,-1911440.758239,
|
||||
-537283.204837,1156565.787585,2518284.974613,2978771.147961,2285191.490698,
|
||||
626136.686773,-1409890.715316,-3038834.772892,-3579162.765425,-2731822.228828,
|
||||
-728915.356799,1718317.328563,3666796.264850,4300394.349825,3265502.159830,
|
||||
847610.742696,-2093758.948552,-4424295.326464,-5166751.952850,-3903146.346575,
|
||||
-984449.218292,2550691.033230,5338008.063395,6207395.378498,4664945.984099,
|
||||
1141905.356234,-3106699.622013,-6440095.078674,-7457334.785992,-5575000.657492,
|
||||
-1322711.048944,3783146.686785,7769327.268660,8958602.684417,6662072.138144,
|
||||
1529858.136359,-4605977.214406,-9372442.351616,-10761660.350202,-7960482.979376,
|
||||
-1766591.537123,5606698.099533,11305779.346088,12927085.482769,9511187.602536,
|
||||
2036388.930375,-6823565.288237,-13637247.864482,-15527597.247686,-11363048.833756,
|
||||
-2342921.824577,8303023.316062,16448700.704063,18650486.048610,13574359.117581,
|
||||
2689991.311114,-10101450.710498,-19838792.204081,-22400528.788313,-16214653.084049,
|
||||
-3081429.850680,12287276.018778,23926421.676653,26903486.467518,19366867.002831,
|
||||
3520957.976311,-14943542.889821,-28854881.491245,-32310300.258257,-23129911.185536,
|
||||
-4011981.690190,18171019.183242,34796853.797034,38802125.311214,27621733.908111,
|
||||
4557312.422997,-22091965.102165,-41960429.245394,-46596369.274924,-32982970.290335,
|
||||
-5158786.517383,26854699.579994,50596356.438136,55953935.730766,39381287.228525,
|
||||
5816755.047390,-32639133.476996,-61006773.393892,-67187912.573574,-47016556.451947,
|
||||
-6529407.091211,39663473.627686,73555723.560159,80673993.102082,56127012.680548,
|
||||
7291879.963058,-48192344.715084,-88681820.564997,-96862974.793882,-66996583.433046,
|
||||
-8095097.920129,58546627.892657,106913500.120816,116295749.303753,79963612.136585,
|
||||
8924265.924556,-71115377.915425,-128887386.814358,-139621279.391140,
|
||||
-95431237.847443,-9756926.457174,86370256.557591,155370411.011265,167618156.945886,
|
||||
113879744.320966,10560464.285645,-104883012.041142,-187286440.462195,
|
||||
-201220454.267134,-135881249.803956,-11288915.420918,127346645.407973,
|
||||
225748346.861610,241548722.121826,162117178.463787,11878900.943144,
|
||||
-154601039.263161,-272096614.921471,-289947157.492990,-193399036.824020,
|
||||
-12244462.331299,187663986.962885,327945826.905572,348028166.863781,
|
||||
230693116.321629,12270520.408649,-227768756.995135,-395240626.753420,
|
||||
-417725794.004062,-275149858.943091,-11804612.586023,276409565.108355,
|
||||
476323094.198962,501359772.474058,328138760.150134,10646479.758475,
|
||||
-335396614.264246,-574013851.836865,-601712311.942546,-391289845.886545,
|
||||
-8534971.317913,406922710.094078,691709700.348455,722120145.317499,
|
||||
466542952.987464,5131609.783276,-493643879.751773,-833501145.234545,
|
||||
-866584864.231526,-556206270.243475,0.00000};
|
||||
|
||||
static char *textdata =
|
||||
"I've seen things you people wouldn't believe. Attack ships on fire off the shoulder of Orion. "
|
||||
"I watched C-beams glitter in the dark near the Tannhäuser Gate. All those moments will be lost "
|
||||
"in time, like tears...in...rain. Time to die.";
|
||||
|
||||
/* Binary I/O for Windows platforms */
|
||||
#ifdef LMP_WIN
|
||||
#include <fcntl.h>
|
||||
unsigned int _CRT_fmode = _O_BINARY;
|
||||
#endif
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
MS3Record *msr = NULL;
|
||||
uint32_t flags = 0;
|
||||
int32_t sinedata[SINE_DATA_SAMPLES];
|
||||
double dsinedata[SINE_DATA_SAMPLES];
|
||||
int idx;
|
||||
int rv;
|
||||
|
||||
/* Create integer and double sine data sets */
|
||||
for (idx = 0; idx < SINE_DATA_SAMPLES; idx++)
|
||||
{
|
||||
sinedata[idx] = (int32_t)(fsinedata[idx]);
|
||||
dsinedata[idx] = (double)(fsinedata[idx]);
|
||||
}
|
||||
|
||||
/* Process command line arguments */
|
||||
if (parameter_proc (argc, argv) < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
if (!(msr = msr3_init (msr)))
|
||||
{
|
||||
ms_log (2, "Could not allocate MS3Record, out of memory?\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set up record parameters */
|
||||
strcpy (msr->sid, "FDSN:XX_TEST__X_Y_Z");
|
||||
msr->reclen = reclen;
|
||||
msr->pubversion = 1;
|
||||
msr->starttime = ms_timestr2nstime ("2012-01-01T00:00:00");
|
||||
msr->samprate = 1.0;
|
||||
msr->encoding = encoding;
|
||||
|
||||
if (encoding == DE_TEXT)
|
||||
{
|
||||
msr->numsamples = strlen (textdata);
|
||||
msr->datasamples = textdata;
|
||||
msr->sampletype = 't';
|
||||
}
|
||||
else if (encoding == DE_FLOAT32)
|
||||
{
|
||||
msr->numsamples = SINE_DATA_SAMPLES;
|
||||
msr->datasamples = fsinedata;
|
||||
msr->sampletype = 'f';
|
||||
}
|
||||
else if (encoding == DE_FLOAT64)
|
||||
{
|
||||
msr->numsamples = SINE_DATA_SAMPLES;
|
||||
msr->datasamples = dsinedata;
|
||||
msr->sampletype = 'd';
|
||||
}
|
||||
else if (encoding == DE_INT16)
|
||||
{
|
||||
msr->numsamples = 220; /* The first 220 samples can be represented in 16-bits */
|
||||
msr->datasamples = sinedata;
|
||||
msr->sampletype = 'i';
|
||||
}
|
||||
else if (encoding == DE_INT32)
|
||||
{
|
||||
msr->numsamples = SINE_DATA_SAMPLES;
|
||||
msr->datasamples = sinedata;
|
||||
msr->sampletype = 'i';
|
||||
}
|
||||
else if (encoding == DE_STEIM1)
|
||||
{
|
||||
msr->numsamples = SINE_DATA_SAMPLES;
|
||||
msr->datasamples = sinedata;
|
||||
msr->sampletype = 'i';
|
||||
}
|
||||
else if (encoding == DE_STEIM2)
|
||||
{
|
||||
msr->numsamples = SINE_DATA_SAMPLES - 1; /* Steim-2 can represent all but the last difference */
|
||||
msr->datasamples = sinedata;
|
||||
msr->sampletype = 'i';
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (2, "Unsupported encoding: %d\n", encoding);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr->samplecnt = msr->numsamples;
|
||||
|
||||
/* Set data flush flag */
|
||||
flags |= MSF_FLUSHDATA;
|
||||
|
||||
/* Set miniSEED v2 if requested */
|
||||
if (msformat == 2)
|
||||
flags |= MSF_PACKVER2;
|
||||
|
||||
rv = msr3_writemseed (msr, outfile, 1, flags, verbose);
|
||||
|
||||
if (rv < 0)
|
||||
ms_log (2, "Error (%d) writing miniSEED to %s\n", rv, outfile);
|
||||
|
||||
/* Make sure everything is cleaned up */
|
||||
msr->datasamples = NULL;
|
||||
msr3_free (&msr);
|
||||
|
||||
return 0;
|
||||
} /* End of main() */
|
||||
|
||||
/***************************************************************************
|
||||
* parameter_proc:
|
||||
*
|
||||
* Process the command line arguments.
|
||||
*
|
||||
* Returns 0 on success, and -1 on failure
|
||||
***************************************************************************/
|
||||
static int
|
||||
parameter_proc (int argcount, char **argvec)
|
||||
{
|
||||
int optind;
|
||||
|
||||
/* Process all command line arguments */
|
||||
for (optind = 1; optind < argcount; optind++)
|
||||
{
|
||||
if (strcmp (argvec[optind], "-V") == 0)
|
||||
{
|
||||
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
|
||||
exit (0);
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-h") == 0)
|
||||
{
|
||||
usage ();
|
||||
exit (0);
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-v", 2) == 0)
|
||||
{
|
||||
verbose += strspn (&argvec[optind][1], "v");
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-F") == 0)
|
||||
{
|
||||
msformat = strtol (argvec[++optind], NULL, 10);
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-r") == 0)
|
||||
{
|
||||
reclen = strtol (argvec[++optind], NULL, 10);
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-e") == 0)
|
||||
{
|
||||
encoding = strtol (argvec[++optind], NULL, 10);
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-o") == 0)
|
||||
{
|
||||
outfile = argvec[++optind];
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (2, "Unknown option: %s\n", argvec[optind]);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure an outfile was specified */
|
||||
if (!outfile)
|
||||
{
|
||||
ms_log (2, "No output file was specified\n\n");
|
||||
ms_log (1, "Try %s -h for usage\n", PACKAGE);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (msformat != 2 && msformat != 3)
|
||||
{
|
||||
ms_log (1, "Specified format must be 2 or 3, version %d is not supported\n", msformat);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Report the program version */
|
||||
if (verbose)
|
||||
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
|
||||
|
||||
return 0;
|
||||
} /* End of parameter_proc() */
|
||||
|
||||
/***************************************************************************
|
||||
* usage:
|
||||
* Print the usage message and exit.
|
||||
***************************************************************************/
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
fprintf (stderr, "%s version: %s\n\n", PACKAGE, VERSION);
|
||||
fprintf (stderr, "Usage: %s [options] -o outfile\n\n", PACKAGE);
|
||||
fprintf (stderr,
|
||||
" ## Options ##\n"
|
||||
" -V Report program version\n"
|
||||
" -h Show this usage message\n"
|
||||
" -v Be more verbose, multiple flags can be used\n"
|
||||
" -F format Specify miniSEED version format, default is v3\n"
|
||||
" -r bytes Specify maximum record length in bytes, default 4096\n"
|
||||
" -e encoding Specify encoding format\n"
|
||||
"\n"
|
||||
" -o outfile Specify the output file, required\n"
|
||||
"\n"
|
||||
"This program packs static, test data into miniSEED\n"
|
||||
"\n");
|
||||
} /* End of usage() */
|
@ -0,0 +1,147 @@
|
||||
/***************************************************************************
|
||||
* A program for illustrating the use of a Trace List as an
|
||||
* intermediate, rolling buffer for production of data records.
|
||||
*
|
||||
* An input file of miniSEED is used as a convenient data source.
|
||||
* MS3Records can be constructed for any arbitrary data and follow the
|
||||
* same pattern of record generation.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libmseed.h>
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* A simple record handler callback function that parses and prints records
|
||||
*
|
||||
***************************************************************************/
|
||||
void
|
||||
record_handler (char *record, int reclen, void *handlerdata)
|
||||
{
|
||||
MS3Record *msr = NULL;
|
||||
|
||||
if (!msr3_parse (record, reclen, &msr, 0, 0))
|
||||
{
|
||||
msr3_print (msr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s() Error parsing record\n", __func__);
|
||||
}
|
||||
|
||||
msr3_free (&msr);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
MS3Record *msr = NULL;
|
||||
MS3TraceList *mstl = NULL;
|
||||
char *inputfile = NULL;
|
||||
uint32_t flags = 0;
|
||||
int8_t verbose = 0;
|
||||
int retcode;
|
||||
|
||||
int64_t psamples;
|
||||
int precords;
|
||||
int reclen = 256; /* Desired maximum record length */
|
||||
uint8_t encoding = DE_STEIM2; /* Desired data encoding */
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
ms_log (2, "Usage: %s <mseedfile>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
inputfile = argv[1];
|
||||
|
||||
mstl = mstl3_init(NULL);
|
||||
if (mstl == NULL)
|
||||
{
|
||||
ms_log (2, "Cannot allocate memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set bit flags to validate CRC and unpack data samples */
|
||||
flags |= MSF_VALIDATECRC;
|
||||
flags |= MSF_UNPACKDATA;
|
||||
|
||||
/* Loop over the input file as a source of data */
|
||||
while ((retcode = ms3_readmsr (&msr, inputfile, flags, verbose)) == MS_NOERROR)
|
||||
{
|
||||
if (mstl3_addmsr (mstl, msr, 0, 1, flags, NULL) == NULL)
|
||||
{
|
||||
ms_log (2, "mstl2_addmsr() had problems\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Attempt to pack data in the Trace List buffer.
|
||||
* Only filled, or complete, records will be generated. */
|
||||
|
||||
ms_log (0, "Calling mstl3_pack() to generate records\n");
|
||||
|
||||
precords = mstl3_pack (mstl, // Pack data in this trace list
|
||||
record_handler, // Callback function that will handle records
|
||||
NULL, // Callback function data, none in this case
|
||||
reclen, // Maximum record length
|
||||
encoding, // Data encoding
|
||||
&psamples, // Packed sample count
|
||||
flags, // Flags to control packing
|
||||
verbose, // Verbosity
|
||||
NULL // Extra headers to inject, none in this case
|
||||
);
|
||||
|
||||
ms_log (0, "mstl3_pack() created %d records containing %" PRId64 " samples\n",
|
||||
precords, psamples);
|
||||
}
|
||||
|
||||
if (retcode != MS_ENDOFFILE)
|
||||
ms_log (2, "Error reading %s: %s\n", inputfile, ms_errorstr (retcode));
|
||||
|
||||
/* Final call to flush data buffers, adding MSF_FLUSHDATA flag */
|
||||
ms_log (0, "Calling mstl3_pack() with MSF_FLUSHDATA flag\n");
|
||||
|
||||
precords = mstl3_pack (mstl, // Pack data in this trace list
|
||||
record_handler, // Callback function that will handle records
|
||||
NULL, // Callback function data, none in this case
|
||||
reclen, // Maximum record length
|
||||
encoding, // Data encoding
|
||||
&psamples, // Packed sample count
|
||||
(flags | MSF_FLUSHDATA), // Flags to control packing, adding flush flag
|
||||
verbose, // Verbosity
|
||||
NULL // Extra headers to inject, none in this case
|
||||
);
|
||||
|
||||
ms_log (0, "Final mstl3_pack() created %d records containing %" PRId64 " samples\n",
|
||||
precords, psamples);
|
||||
|
||||
/* Make sure everything is cleaned up */
|
||||
ms3_readmsr (&msr, NULL, flags, 0);
|
||||
|
||||
if (msr)
|
||||
msr3_free (&msr);
|
||||
|
||||
if (mstl)
|
||||
mstl3_free (&mstl, 0);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
/***************************************************************************
|
||||
* A simple example of using libmseed to read miniSEED in parallel
|
||||
* using re-entrant interfaces and POSIX threading.
|
||||
*
|
||||
* Windows is not supported.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <libmseed.h>
|
||||
|
||||
/* File read test portability, possibly in the future */
|
||||
#if defined(LMP_WIN)
|
||||
#define _access access
|
||||
#define R_OK 4 /* Test for read permission */
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define VERSION "[libmseed " LIBMSEED_VERSION " example]"
|
||||
#define PACKAGE "lm_pararead"
|
||||
|
||||
static int8_t verbose = 0;
|
||||
static int8_t printrecs = 0;
|
||||
static uint32_t readflags = 0;
|
||||
|
||||
/* File information structure */
|
||||
typedef struct FileEntry
|
||||
{
|
||||
char *filename;
|
||||
pthread_t tid;
|
||||
MS3TraceList *mstl;
|
||||
uint64_t recordcount;
|
||||
int result;
|
||||
struct FileEntry *next;
|
||||
} FileEntry;
|
||||
|
||||
/* List of files to read */
|
||||
static FileEntry *files = NULL;
|
||||
|
||||
/* Thread function to read miniSEED file */
|
||||
static void *ReadMSFileThread (void *vfe)
|
||||
{
|
||||
FileEntry *fe = (FileEntry *)vfe;
|
||||
MS3FileParam *msfp = NULL;
|
||||
MS3Record *msr = NULL;
|
||||
|
||||
/* NOTE: This example is contrived for illustration.
|
||||
* The combination of ms3_readmsr_r() with mstl3_addmsr()
|
||||
* is only needed if you wish to do something for each record.
|
||||
* Otherwise, consider using ms3_readtracelist() if only
|
||||
* a MS3TraceList is desired.*/
|
||||
|
||||
/* Loop over the input file record by record */
|
||||
while ((fe->result = ms3_readmsr_r (&msfp, &msr,
|
||||
fe->filename,
|
||||
readflags, verbose)) == MS_NOERROR)
|
||||
{
|
||||
fe->recordcount++;
|
||||
|
||||
if (printrecs > 0)
|
||||
msr3_print (msr, printrecs - 1);
|
||||
|
||||
/* Add record to trace list */
|
||||
if (mstl3_addmsr (fe->mstl, msr, 0, 1, 0, NULL) == NULL)
|
||||
{
|
||||
ms_log (2, "Error adding record to list\n");
|
||||
fe->result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure everything is cleaned up */
|
||||
ms3_readmsr_r (&msfp, &msr, NULL, 0, 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
FileEntry *fe = NULL;
|
||||
int idx;
|
||||
|
||||
/* Simplistic argument parsing */
|
||||
for (idx = 1; idx < argc; idx++)
|
||||
{
|
||||
if (strncmp (argv[idx], "-v", 2) == 0)
|
||||
verbose += strspn (&argv[idx][1], "v");
|
||||
else if (strncmp (argv[idx], "-p", 2) == 0)
|
||||
printrecs += strspn (&argv[idx][1], "p");
|
||||
else
|
||||
{
|
||||
/* Add read-able files to file entry list */
|
||||
if (access(argv[idx], R_OK) == 0)
|
||||
{
|
||||
if ((fe = (FileEntry *)malloc(sizeof(FileEntry))) == NULL)
|
||||
{
|
||||
ms_log (2, "Error allocating memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fe->filename = argv[idx];
|
||||
fe->mstl = mstl3_init(NULL);
|
||||
fe->recordcount = 0;
|
||||
fe->result = 0;
|
||||
fe->next = files;
|
||||
|
||||
files = fe;
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (2, "Cannot find file: %s\n", argv[idx]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure input file(s) specified */
|
||||
if (!files)
|
||||
{
|
||||
ms_log (1, "No input file(s) specified\n\n");
|
||||
ms_log (1, "%s version %s\n\n", PACKAGE, VERSION);
|
||||
ms_log (1, "Read specified miniSEED files in parallel\n\n");
|
||||
ms_log (1, "Usage: %s [-p] [-v] file1 [file2 .. fileN]\n", PACKAGE);
|
||||
ms_log (1, " -v Be more verbose, multiple flags can be used\n");
|
||||
ms_log (1, " -p Print record details, multiple flags can be used\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Report the program version */
|
||||
if (verbose)
|
||||
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
|
||||
|
||||
/* Add program name and version to User-Agent for URL-based requests */
|
||||
if (libmseed_url_support() && ms3_url_useragent(PACKAGE, VERSION))
|
||||
return -1;
|
||||
|
||||
/* Set flag to validate CRCs when reading */
|
||||
readflags |= MSF_VALIDATECRC;
|
||||
|
||||
/* Parse byte range from file/URL path name if present */
|
||||
readflags |= MSF_PNAMERANGE;
|
||||
|
||||
/* Create a thread to read each file */
|
||||
for (fe = files; fe; fe = fe->next)
|
||||
{
|
||||
pthread_create (&(fe->tid), NULL, ReadMSFileThread, fe);
|
||||
}
|
||||
|
||||
/* Wait for threads to finish */
|
||||
for (fe = files; fe; fe = fe->next)
|
||||
{
|
||||
pthread_join(fe->tid, NULL);
|
||||
}
|
||||
|
||||
/* Report details for each file */
|
||||
for (fe = files; fe; fe = fe->next)
|
||||
{
|
||||
ms_log (0, "%s: records: %" PRIu64" result: %d\n",
|
||||
fe->filename, fe->recordcount, fe->result);
|
||||
|
||||
if (fe->result == MS_NOERROR || fe->result == MS_ENDOFFILE)
|
||||
mstl3_printtracelist (fe->mstl, ISOMONTHDAY, 1, 1, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* End of main() */
|
@ -0,0 +1,309 @@
|
||||
/***************************************************************************
|
||||
* A program for libmseed parsing tests.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <libmseed.h>
|
||||
|
||||
#define PACKAGE "lm_parse"
|
||||
#define VERSION "[libmseed " LIBMSEED_VERSION " " PACKAGE " ]"
|
||||
|
||||
static flag verbose = 0;
|
||||
static flag ppackets = 0;
|
||||
static flag basicsum = 0;
|
||||
static flag tracegap = 0;
|
||||
static flag splitversion = 0;
|
||||
static int printraw = 0;
|
||||
static int printdata = 0;
|
||||
static int reclen = -1;
|
||||
static char *inputfile = NULL;
|
||||
|
||||
static int parameter_proc (int argcount, char **argvec);
|
||||
static void usage (void);
|
||||
|
||||
/* Binary I/O for Windows platforms */
|
||||
#ifdef LMP_WIN
|
||||
#include <fcntl.h>
|
||||
unsigned int _CRT_fmode = _O_BINARY;
|
||||
#endif
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
MS3TraceList *mstl = 0;
|
||||
MS3Record *msr = 0;
|
||||
uint32_t flags = 0;
|
||||
|
||||
int64_t totalrecs = 0;
|
||||
int64_t totalsamps = 0;
|
||||
int retcode;
|
||||
|
||||
/* Process command line arguments */
|
||||
if (parameter_proc (argc, argv) < 0)
|
||||
return -1;
|
||||
|
||||
/* Validate CRC and unpack data samples */
|
||||
flags |= MSF_VALIDATECRC;
|
||||
|
||||
/* Parse byte range from file/URL path name if present */
|
||||
flags |= MSF_PNAMERANGE;
|
||||
|
||||
if (printdata)
|
||||
flags |= MSF_UNPACKDATA;
|
||||
|
||||
if (tracegap)
|
||||
mstl = mstl3_init (NULL);
|
||||
|
||||
/* Loop over the input file */
|
||||
while ((retcode = ms3_readmsr (&msr, inputfile, flags, verbose)) == MS_NOERROR)
|
||||
{
|
||||
totalrecs++;
|
||||
totalsamps += msr->samplecnt;
|
||||
|
||||
if (tracegap)
|
||||
{
|
||||
mstl3_addmsr (mstl, msr, splitversion, 1, flags, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( printraw )
|
||||
{
|
||||
if (msr->formatversion == 3)
|
||||
ms_parse_raw3 (msr->record, msr->reclen, ppackets);
|
||||
else
|
||||
ms_parse_raw2 (msr->record, msr->reclen, ppackets, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
msr3_print (msr, ppackets);
|
||||
}
|
||||
|
||||
if (printdata && msr->numsamples > 0)
|
||||
{
|
||||
int line, col, cnt, samplesize;
|
||||
int lines = (msr->numsamples / 6) + 1;
|
||||
void *sptr;
|
||||
|
||||
if ((samplesize = ms_samplesize (msr->sampletype)) == 0)
|
||||
{
|
||||
ms_log (2, "Unrecognized sample type: '%c'\n", msr->sampletype);
|
||||
}
|
||||
if (msr->sampletype == 't')
|
||||
{
|
||||
char *text = (char *)msr->datasamples;
|
||||
int length = msr->numsamples;
|
||||
|
||||
ms_log (0, "Text data:\n");
|
||||
|
||||
/* Print maximum log message segments */
|
||||
while (length > (MAX_LOG_MSG_LENGTH - 1))
|
||||
{
|
||||
ms_log (0, "%.*s", (MAX_LOG_MSG_LENGTH - 1), text);
|
||||
text += MAX_LOG_MSG_LENGTH - 1;
|
||||
length -= MAX_LOG_MSG_LENGTH - 1;
|
||||
}
|
||||
|
||||
/* Print any remaining TEXT and add a newline */
|
||||
if (length > 0)
|
||||
{
|
||||
ms_log (0, "%.*s\n", length, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (0, "\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
for (cnt = 0, line = 0; line < lines; line++)
|
||||
{
|
||||
for (col = 0; col < 6; col++)
|
||||
{
|
||||
if (cnt < msr->numsamples)
|
||||
{
|
||||
sptr = (char *)msr->datasamples + (cnt * samplesize);
|
||||
|
||||
if (msr->sampletype == 'i')
|
||||
ms_log (0, "%10d ", *(int32_t *)sptr);
|
||||
|
||||
else if (msr->sampletype == 'f')
|
||||
ms_log (0, "%10.8g ", *(float *)sptr);
|
||||
|
||||
else if (msr->sampletype == 'd')
|
||||
ms_log (0, "%10.10g ", *(double *)sptr);
|
||||
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
ms_log (0, "\n");
|
||||
|
||||
/* If only printing the first 6 samples break out here */
|
||||
if (printdata == 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (retcode != MS_ENDOFFILE)
|
||||
ms_log (2, "Cannot read %s: %s\n", inputfile, ms_errorstr (retcode));
|
||||
|
||||
if (tracegap)
|
||||
mstl3_printtracelist (mstl, ISOMONTHDAY_Z, 1, 1, splitversion);
|
||||
|
||||
/* Make sure everything is cleaned up */
|
||||
ms3_readmsr (&msr, NULL, flags, 0);
|
||||
|
||||
if (mstl)
|
||||
mstl3_free (&mstl, 0);
|
||||
|
||||
if (basicsum)
|
||||
ms_log (1, "Records: %" PRId64 ", Samples: %" PRId64 "\n",
|
||||
totalrecs, totalsamps);
|
||||
|
||||
return 0;
|
||||
} /* End of main() */
|
||||
|
||||
/***************************************************************************
|
||||
* parameter_proc():
|
||||
* Process the command line arguments.
|
||||
*
|
||||
* Returns 0 on success, and -1 on failure
|
||||
***************************************************************************/
|
||||
static int
|
||||
parameter_proc (int argcount, char **argvec)
|
||||
{
|
||||
int optind;
|
||||
|
||||
/* Process all command line arguments */
|
||||
for (optind = 1; optind < argcount; optind++)
|
||||
{
|
||||
if (strcmp (argvec[optind], "-V") == 0)
|
||||
{
|
||||
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
|
||||
exit (0);
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-h") == 0)
|
||||
{
|
||||
usage ();
|
||||
exit (0);
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-v", 2) == 0)
|
||||
{
|
||||
verbose += strspn (&argvec[optind][1], "v");
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-p", 2) == 0)
|
||||
{
|
||||
ppackets += strspn (&argvec[optind][1], "p");
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-z", 2) == 0)
|
||||
{
|
||||
printraw = 1;
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-d", 2) == 0)
|
||||
{
|
||||
printdata = 1;
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-D", 2) == 0)
|
||||
{
|
||||
printdata = 2;
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-P") == 0)
|
||||
{
|
||||
splitversion = 1;
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-tg", 3) == 0)
|
||||
{
|
||||
tracegap = 1;
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-s") == 0)
|
||||
{
|
||||
basicsum = 1;
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-r") == 0)
|
||||
{
|
||||
reclen = atoi (argvec[++optind]);
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-", 1) == 0 &&
|
||||
strlen (argvec[optind]) > 1)
|
||||
{
|
||||
ms_log (2, "Unknown option: %s\n", argvec[optind]);
|
||||
exit (1);
|
||||
}
|
||||
else if (inputfile == NULL)
|
||||
{
|
||||
inputfile = argvec[optind];
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (2, "Unknown option: %s\n", argvec[optind]);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure an inputfile was specified */
|
||||
if (!inputfile)
|
||||
{
|
||||
ms_log (2, "No input file was specified\n\n");
|
||||
ms_log (1, "%s version %s\n\n", PACKAGE, VERSION);
|
||||
ms_log (1, "Try %s -h for usage\n", PACKAGE);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Add program name and version to User-Agent for URL-based requests */
|
||||
if (libmseed_url_support() && ms3_url_useragent(PACKAGE, VERSION))
|
||||
return -1;
|
||||
|
||||
/* Report the program version */
|
||||
if (verbose)
|
||||
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
|
||||
|
||||
return 0;
|
||||
} /* End of parameter_proc() */
|
||||
|
||||
/***************************************************************************
|
||||
* usage():
|
||||
* Print the usage message and exit.
|
||||
***************************************************************************/
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
fprintf (stderr, "%s version: %s\n\n", PACKAGE, VERSION);
|
||||
fprintf (stderr, "Usage: %s [options] file\n\n", PACKAGE);
|
||||
fprintf (stderr,
|
||||
" ## Options ##\n"
|
||||
" -V Report program version\n"
|
||||
" -h Show this usage message\n"
|
||||
" -v Be more verbose, multiple flags can be used\n"
|
||||
" -p Print details of header, multiple flags can be used\n"
|
||||
" -z Print raw details of header\n"
|
||||
" -d Print first 6 sample values\n"
|
||||
" -D Print all sample values\n"
|
||||
" -P Additionally group traces by data publication version\n"
|
||||
" -tg Print trace listing with gap information\n"
|
||||
" -s Print a basic summary after processing a file\n"
|
||||
" -r bytes Specify record length in bytes, required if no Blockette 1000\n"
|
||||
"\n"
|
||||
" file File of miniSEED records\n"
|
||||
"\n");
|
||||
} /* End of usage() */
|
@ -0,0 +1,320 @@
|
||||
/***************************************************************************
|
||||
* A program illustrating reading miniSEED from buffers
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libmseed.h>
|
||||
#define TESTCPPDLL_API __declspec(dllexport)
|
||||
|
||||
TESTCPPDLL_API int __stdcall MseedDatas (int argc, char **argv) // MseedDatas(char *argv, int length)
|
||||
{
|
||||
struct stat sb = {0};
|
||||
int64_t records = 0;
|
||||
FILE *fh;
|
||||
|
||||
MS3TraceList *mstl = NULL;
|
||||
char *buffer = NULL;
|
||||
uint64_t bufferlength = 0;
|
||||
int8_t splitversion = 0;
|
||||
uint32_t flags = 0;
|
||||
int8_t verbose = 0;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
ms_log (2, "%s requires a single file name argument\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read specified file into buffer */
|
||||
if (!(fh = fopen (argv[1], "rb")))
|
||||
{
|
||||
ms_log (2, "Error opening %s: %s\n", argv[1], strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
if (fstat (fileno (fh), &sb))
|
||||
{
|
||||
ms_log (2, "Error stating %s: %s\n", argv[1], strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
if (!(buffer = (char *)malloc (sb.st_size)))
|
||||
{
|
||||
ms_log (2, "Error allocating buffer of %" PRIsize_t " bytes\n",
|
||||
(sb.st_size >= 0) ? (size_t)sb.st_size : 0);
|
||||
return -1;
|
||||
}
|
||||
if (fread (buffer, sb.st_size, 1, fh) != 1)
|
||||
{
|
||||
ms_log (2, "Error reading file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose (fh);
|
||||
|
||||
bufferlength = sb.st_size;
|
||||
|
||||
/* Set bit flags to validate CRC and unpack data samples */
|
||||
flags |= MSF_VALIDATECRC;
|
||||
flags |= MSF_UNPACKDATA;
|
||||
|
||||
mstl = mstl3_init (NULL);
|
||||
|
||||
if (!mstl)
|
||||
{
|
||||
ms_log (2, "Error allocating MS3TraceList\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read all miniSEED in buffer, accumulate in MS3TraceList */
|
||||
records = mstl3_readbuffer (&mstl, buffer, bufferlength,
|
||||
splitversion, flags, NULL, verbose);
|
||||
|
||||
if (records < 0)
|
||||
{
|
||||
ms_log (2, "Problem reading miniSEED from buffer: %s\n", ms_errorstr (records));
|
||||
}
|
||||
|
||||
/* Print summary */
|
||||
mstl3_printtracelist (mstl, ISOMONTHDAY, 1, 1, 0);
|
||||
|
||||
ms_log (1, "Total records: %" PRId64 "\n", records);
|
||||
|
||||
/* Make sure everything is cleaned up */
|
||||
if (mstl)
|
||||
mstl3_free (&mstl, 0);
|
||||
|
||||
free (buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct AsciiDataStruct
|
||||
{
|
||||
char *sid;
|
||||
char *starttime; //!< Time of first sample
|
||||
char *endtime; //!< Time of last sample
|
||||
double samprate; //!< Nominal sample rate (Hz)
|
||||
int64_t samplecnt; //!< Number of samples in trace coverage
|
||||
size_t datasize; //!< Size of datasamples buffer in bytes
|
||||
int64_t numsamples; //!< Number of data samples in datasamples
|
||||
char sampletype; //!< Sample type code, see @ref sample-types
|
||||
uint8_t samplesize;
|
||||
void *datasamples; //!< Data samples, \a numsamples of type \a sampletype
|
||||
} AsciiDataStruct;
|
||||
typedef void (__stdcall *generalDataFunction) (AsciiDataStruct AsciiData);
|
||||
|
||||
generalDataFunction generalData;
|
||||
|
||||
TESTCPPDLL_API void __stdcall MseedDatasCallFun (generalDataFunction fn)
|
||||
{
|
||||
generalData = fn;
|
||||
}
|
||||
TESTCPPDLL_API int __stdcall bufferMseedData (int argc, char *argv)
|
||||
{
|
||||
struct stat sb = {0};
|
||||
int64_t records = 0;
|
||||
FILE *fh;
|
||||
|
||||
MS3TraceList *mstl = NULL;
|
||||
char *buffer = NULL;
|
||||
uint64_t bufferlength = 0;
|
||||
int8_t splitversion = 0;
|
||||
uint32_t flags = 0;
|
||||
int8_t verbose = 0;
|
||||
|
||||
// if (argc != 2)
|
||||
//{
|
||||
// ms_log (2, "%s requires a single file name argument\n", argv[0]);
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
/* Read specified file into buffer
|
||||
if (!(fh = fopen (argv[1], "rb")))
|
||||
{
|
||||
ms_log (2, "Error opening %s: %s\n", argv[1], strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
if (fstat (fileno (fh), &sb))
|
||||
{
|
||||
ms_log (2, "Error stating %s: %s\n", argv[1], strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
if (!(buffer = (char *)malloc (sb.st_size)))
|
||||
{
|
||||
ms_log (2, "Error allocating buffer of %" PRIsize_t " bytes\n",
|
||||
(sb.st_size >= 0) ? (size_t)sb.st_size : 0);
|
||||
return -1;
|
||||
}
|
||||
if (fread (buffer, sb.st_size, 1, fh) != 1)
|
||||
{
|
||||
ms_log (2, "Error reading file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose (fh);
|
||||
*/
|
||||
bufferlength = argc;
|
||||
// buffer = argv;
|
||||
/* Set bit flags to validate CRC and unpack data samples */
|
||||
flags |= MSF_VALIDATECRC;
|
||||
flags |= MSF_UNPACKDATA;
|
||||
|
||||
mstl = mstl3_init (NULL);
|
||||
|
||||
if (!mstl)
|
||||
{
|
||||
ms_log (2, "Error allocating MS3TraceList\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read all miniSEED in buffer, accumulate in MS3TraceList */
|
||||
records = mstl3_readbuffer (&mstl, argv, bufferlength,
|
||||
splitversion, flags, NULL, verbose);
|
||||
|
||||
if (records < 0)
|
||||
{
|
||||
ms_log (2, "Problem reading miniSEED from buffer: %s\n", ms_errorstr (records));
|
||||
}
|
||||
|
||||
/* Print summary */
|
||||
// mstl3_printtracelist (mstl, ISOMONTHDAY, 1, 1, 0);
|
||||
|
||||
/* Traverse trace list structures and print summary information */
|
||||
MS3TraceID *tid = mstl->traces.next[0];
|
||||
char starttimestr[30];
|
||||
char endtimestr[30];
|
||||
MS3TraceSeg *seg = NULL;
|
||||
MS3RecordPtr *recptr = NULL;
|
||||
|
||||
char *mseedfile = NULL;
|
||||
char bufferptrstr[30];
|
||||
char fileptrstr[30];
|
||||
size_t idx;
|
||||
int rv;
|
||||
|
||||
char printdata = 'd';
|
||||
int64_t unpacked;
|
||||
uint8_t samplesize;
|
||||
char sampletype;
|
||||
size_t lineidx;
|
||||
size_t lines;
|
||||
int col;
|
||||
void *sptr;
|
||||
AsciiDataStruct ybbmqj;
|
||||
/* Traverse trace list structures and print summary information */
|
||||
tid = mstl->traces.next[0];
|
||||
while (tid)
|
||||
{
|
||||
ms_log (0, "TraceID for %s (%d), segments: %u\n",
|
||||
tid->sid, tid->pubversion, tid->numsegments);
|
||||
|
||||
seg = tid->first;
|
||||
while (seg)
|
||||
{
|
||||
if (!ms_nstime2timestr (seg->starttime, starttimestr, ISOMONTHDAY, NANO) ||
|
||||
!ms_nstime2timestr (seg->endtime, endtimestr, ISOMONTHDAY, NANO))
|
||||
{
|
||||
ms_log (2, "Cannot create time strings\n");
|
||||
starttimestr[0] = endtimestr[0] = '\0';
|
||||
}
|
||||
|
||||
ms_log (0, " Segment %s - %s, samples: %" PRId64 ", sample rate: %g\n",
|
||||
starttimestr, endtimestr, seg->samplecnt, seg->samprate);
|
||||
|
||||
unpacked = seg->numsamples; // mstl3_unpack_recordlist (tid, seg, NULL, 0, verbose);
|
||||
sampletype = seg->sampletype;
|
||||
samplesize = ms_samplesize (seg->sampletype);
|
||||
|
||||
if (unpacked != seg->samplecnt)
|
||||
{
|
||||
ms_log (2, "Cannot unpack samples for %s\n", tid->sid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (0, "DATA (%" PRId64 " samples) of type '%c':\n", seg->numsamples, seg->sampletype);
|
||||
|
||||
if (sampletype == 't')
|
||||
{
|
||||
printf ("%*s",
|
||||
(seg->numsamples > INT_MAX) ? INT_MAX : (int)seg->numsamples,
|
||||
(char *)seg->datasamples);
|
||||
}
|
||||
else
|
||||
{
|
||||
ybbmqj.sid = tid->sid;
|
||||
ybbmqj.starttime = starttimestr;
|
||||
ybbmqj.endtime = endtimestr;
|
||||
ybbmqj.samprate = seg->samprate;
|
||||
ybbmqj.samplecnt = seg->samplecnt;
|
||||
ybbmqj.datasamples = seg->datasamples;
|
||||
ybbmqj.numsamples = seg->numsamples;
|
||||
ybbmqj.datasize = seg->datasize;
|
||||
ybbmqj.samplesize = samplesize;
|
||||
ybbmqj.sampletype = seg->sampletype;
|
||||
if (generalData != NULL)
|
||||
{
|
||||
generalData (ybbmqj);
|
||||
}
|
||||
lines = (unpacked / 6) + 1;
|
||||
//for (idx = 0, lineidx = 0; lineidx < lines; lineidx++)
|
||||
//{
|
||||
// for (col = 0; col < 6 && idx < seg->numsamples; col++)
|
||||
// {
|
||||
// sptr = (char *)seg->datasamples + (idx * samplesize);
|
||||
|
||||
// if (sampletype == 'i')
|
||||
// ms_log (0, "%10d ", *(int32_t *)sptr);
|
||||
|
||||
// else if (sampletype == 'f')
|
||||
// ms_log (0, "%10.8g ", *(float *)sptr);
|
||||
|
||||
// else if (sampletype == 'd')
|
||||
// ms_log (0, "%10.10g ", *(double *)sptr);
|
||||
|
||||
// idx++;
|
||||
// }
|
||||
// ms_log (0, "\n");
|
||||
|
||||
// // if (printdata == 'd')
|
||||
// // break;
|
||||
//}
|
||||
}
|
||||
seg = seg->next;
|
||||
}
|
||||
}
|
||||
tid = tid->next[0];
|
||||
}
|
||||
//****************************************************
|
||||
|
||||
ms_log (1, "Total records: %" PRId64 "\n", records);
|
||||
|
||||
/* Make sure everything is cleaned up */
|
||||
if (mstl)
|
||||
mstl3_free (&mstl, 0);
|
||||
|
||||
free (buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,204 @@
|
||||
/***************************************************************************
|
||||
* A program for reading miniSEED into a trace list followed by
|
||||
* unpacking from an associated record list.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libmseed.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
MS3TraceList *mstl = NULL;
|
||||
MS3TraceID *tid = NULL;
|
||||
MS3TraceSeg *seg = NULL;
|
||||
MS3RecordPtr *recptr = NULL;
|
||||
|
||||
char *mseedfile = NULL;
|
||||
char starttimestr[30];
|
||||
char endtimestr[30];
|
||||
char bufferptrstr[30];
|
||||
char fileptrstr[30];
|
||||
uint32_t flags = 0;
|
||||
int8_t verbose = 0;
|
||||
size_t idx;
|
||||
int rv;
|
||||
|
||||
char printdata = 0;
|
||||
int64_t unpacked;
|
||||
uint8_t samplesize;
|
||||
char sampletype;
|
||||
size_t lineidx;
|
||||
size_t lines;
|
||||
int col;
|
||||
void *sptr;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
ms_log (2, "Usage: %s <mseedfile> [-v] [-d] [-D]\n",argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mseedfile = argv[1];
|
||||
|
||||
/* Simplistic argument parsing */
|
||||
for (idx = 2; idx < argc; idx++)
|
||||
{
|
||||
if (strncmp (argv[idx], "-v", 2) == 0)
|
||||
verbose += strspn (&argv[idx][1], "v");
|
||||
else if (strncmp (argv[idx], "-d", 2) == 0)
|
||||
printdata = 'd';
|
||||
else if (strncmp (argv[idx], "-D", 2) == 0)
|
||||
printdata = 'D';
|
||||
}
|
||||
|
||||
/* Set bit flag to validate CRC */
|
||||
flags |= MSF_VALIDATECRC;
|
||||
|
||||
/* Set bit flag to build a record list */
|
||||
flags |= MSF_RECORDLIST;
|
||||
|
||||
/* Read all miniSEED into a trace list, limiting to selections */
|
||||
rv = ms3_readtracelist (&mstl, mseedfile, NULL, 0, flags, verbose);
|
||||
|
||||
if (rv != MS_NOERROR)
|
||||
{
|
||||
ms_log (2, "Cannot read miniSEED from file: %s\n", ms_errorstr(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Traverse trace list structures and print summary information */
|
||||
tid = mstl->traces.next[0];
|
||||
while (tid)
|
||||
{
|
||||
ms_log (0, "TraceID for %s (%d), segments: %u\n",
|
||||
tid->sid, tid->pubversion, tid->numsegments);
|
||||
|
||||
seg = tid->first;
|
||||
while (seg)
|
||||
{
|
||||
if (!ms_nstime2timestr (seg->starttime, starttimestr, ISOMONTHDAY, NANO) ||
|
||||
!ms_nstime2timestr (seg->endtime, endtimestr, ISOMONTHDAY, NANO))
|
||||
{
|
||||
ms_log (2, "Cannot create time strings\n");
|
||||
starttimestr[0] = endtimestr[0] = '\0';
|
||||
}
|
||||
|
||||
ms_log (0, " Segment %s - %s, samples: %" PRId64 ", sample rate: %g\n",
|
||||
starttimestr, endtimestr, seg->samplecnt, seg->samprate);
|
||||
|
||||
if (seg->recordlist)
|
||||
{
|
||||
ms_log (0, " Record list:\n");
|
||||
|
||||
/* Traverse record list print summary information */
|
||||
recptr = seg->recordlist->first;
|
||||
while (recptr)
|
||||
{
|
||||
if (recptr->bufferptr == NULL)
|
||||
strcpy (bufferptrstr, "NULL");
|
||||
else
|
||||
snprintf (bufferptrstr, sizeof(bufferptrstr), "%" PRIu64, (uint64_t)recptr->bufferptr);
|
||||
|
||||
if (recptr->fileptr == NULL)
|
||||
strcpy (fileptrstr, "NULL");
|
||||
else
|
||||
snprintf (fileptrstr, sizeof(fileptrstr), "%" PRIu64, (uint64_t)recptr->fileptr);
|
||||
|
||||
ms_log (0, " RECORD: bufferptr: %s, fileptr: %s, filename: %s, fileoffset: %"PRId64"\n",
|
||||
bufferptrstr, fileptrstr, recptr->filename, recptr->fileoffset);
|
||||
ms_nstime2timestr (recptr->msr->starttime, starttimestr, ISOMONTHDAY_Z, NANO);
|
||||
ms_nstime2timestr (recptr->endtime, endtimestr, ISOMONTHDAY_Z, NANO);
|
||||
ms_log (0, " Start: %s, End: %s\n", starttimestr, endtimestr);
|
||||
|
||||
recptr = recptr->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unpack and print samples for this trace segment */
|
||||
if (printdata && seg->recordlist && seg->recordlist->first)
|
||||
{
|
||||
/* Determine sample size and type based on encoding of first record */
|
||||
ms_encoding_sizetype (seg->recordlist->first->msr->encoding, &samplesize, &sampletype);
|
||||
|
||||
/* Unpack data samples using record list.
|
||||
* No data buffer is supplied, so it will be allocated and assigned to the segment.
|
||||
* Alternatively, a user-specified data buffer can be provided here. */
|
||||
unpacked = mstl3_unpack_recordlist (tid, seg, NULL, 0, verbose);
|
||||
|
||||
if (unpacked != seg->samplecnt)
|
||||
{
|
||||
ms_log (2, "Cannot unpack samples for %s\n", tid->sid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (0, "DATA (%" PRId64 " samples) of type '%c':\n", seg->numsamples, seg->sampletype);
|
||||
|
||||
if (sampletype == 't')
|
||||
{
|
||||
printf ("%*s",
|
||||
(seg->numsamples > INT_MAX) ? INT_MAX : (int)seg->numsamples,
|
||||
(char *)seg->datasamples);
|
||||
}
|
||||
else
|
||||
{
|
||||
lines = (unpacked / 6) + 1;
|
||||
|
||||
for (idx = 0, lineidx = 0; lineidx < lines; lineidx++)
|
||||
{
|
||||
for (col = 0; col < 6 && idx < seg->numsamples; col++)
|
||||
{
|
||||
sptr = (char *)seg->datasamples + (idx * samplesize);
|
||||
|
||||
if (sampletype == 'i')
|
||||
ms_log (0, "%10d ", *(int32_t *)sptr);
|
||||
|
||||
else if (sampletype == 'f')
|
||||
ms_log (0, "%10.8g ", *(float *)sptr);
|
||||
|
||||
else if (sampletype == 'd')
|
||||
ms_log (0, "%10.10g ", *(double *)sptr);
|
||||
|
||||
idx++;
|
||||
}
|
||||
ms_log (0, "\n");
|
||||
|
||||
if (printdata == 'd')
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
seg = seg->next;
|
||||
}
|
||||
|
||||
tid = tid->next[0];
|
||||
}
|
||||
|
||||
/* Make sure everything is cleaned up */
|
||||
if (mstl)
|
||||
mstl3_free (&mstl, 0);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/***************************************************************************
|
||||
* A program for reading miniSEED using data selections to limit which
|
||||
* data is read. This program also illustrates traversing a trace
|
||||
* list.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libmseed.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
MS3Selections *selections = NULL;
|
||||
MS3TraceList *mstl = NULL;
|
||||
MS3TraceID *tid = NULL;
|
||||
MS3TraceSeg *seg = NULL;
|
||||
|
||||
char *mseedfile = NULL;
|
||||
char *selectionfile = NULL;
|
||||
char starttimestr[30];
|
||||
char endtimestr[30];
|
||||
uint32_t flags = 0;
|
||||
int8_t verbose = 0;
|
||||
int rv;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
ms_log (2, "Usage: %s <mseedfile> <selectionfile>\n",argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mseedfile = argv[1];
|
||||
selectionfile = argv[2];
|
||||
|
||||
/* Read data selections from specified file */
|
||||
if (ms3_readselectionsfile (&selections, selectionfile) < 0)
|
||||
{
|
||||
ms_log (2, "Cannot read data selection file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set bit flags to validate CRC and unpack data samples */
|
||||
flags |= MSF_VALIDATECRC;
|
||||
flags |= MSF_UNPACKDATA;
|
||||
|
||||
/* Read all miniSEED into a trace list, limiting to selections */
|
||||
rv = ms3_readtracelist_selection (&mstl, mseedfile, NULL,
|
||||
selections, 0, flags, verbose);
|
||||
|
||||
if (rv != MS_NOERROR)
|
||||
{
|
||||
ms_log (2, "Cannot read miniSEED from file: %s\n", ms_errorstr(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Traverse trace list structures and print summary information */
|
||||
tid = mstl->traces.next[0];
|
||||
while (tid)
|
||||
{
|
||||
if (!ms_nstime2timestr (tid->earliest, starttimestr, SEEDORDINAL, NANO_MICRO_NONE) ||
|
||||
!ms_nstime2timestr (tid->latest, endtimestr, SEEDORDINAL, NANO_MICRO_NONE))
|
||||
{
|
||||
ms_log (2, "Cannot create time strings\n");
|
||||
starttimestr[0] = endtimestr[0] = '\0';
|
||||
}
|
||||
|
||||
ms_log (0, "TraceID for %s (%d), earliest: %s, latest: %s, segments: %u\n",
|
||||
tid->sid, tid->pubversion, starttimestr, endtimestr, tid->numsegments);
|
||||
|
||||
seg = tid->first;
|
||||
while (seg)
|
||||
{
|
||||
if (!ms_nstime2timestr (seg->starttime, starttimestr, SEEDORDINAL, NANO_MICRO_NONE) ||
|
||||
!ms_nstime2timestr (seg->endtime, endtimestr, SEEDORDINAL, NANO_MICRO_NONE))
|
||||
{
|
||||
ms_log (2, "Cannot create time strings\n");
|
||||
starttimestr[0] = endtimestr[0] = '\0';
|
||||
}
|
||||
|
||||
ms_log (0, " Segment %s - %s, samples: %" PRId64 ", sample rate: %g, sample type: %c\n",
|
||||
starttimestr, endtimestr, seg->numsamples, seg->samprate,
|
||||
(seg->sampletype) ? seg->sampletype : ' ');
|
||||
|
||||
seg = seg->next;
|
||||
}
|
||||
|
||||
tid = tid->next[0];
|
||||
}
|
||||
|
||||
/* Make sure everything is cleaned up */
|
||||
if (mstl)
|
||||
mstl3_free (&mstl, 0);
|
||||
|
||||
if (selections)
|
||||
ms3_freeselections (selections);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/***************************************************************************
|
||||
* A program illustrating mapping source identifiers and SEED codes
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <libmseed.h>
|
||||
|
||||
int
|
||||
map_sid (char *original_sid)
|
||||
{
|
||||
char sid[LM_SIDLEN];
|
||||
char network[11];
|
||||
char station[11];
|
||||
char location[11];
|
||||
char channel[31];
|
||||
int rv;
|
||||
|
||||
/* Parse network, station, location and channel from SID */
|
||||
rv = ms_sid2nslc (original_sid, network, station, location, channel);
|
||||
|
||||
if (rv)
|
||||
{
|
||||
printf ("Error returned ms_sid2nslc()\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Construct SID from network, station, location and channel */
|
||||
rv = ms_nslc2sid (sid, sizeof(sid), 0, network, station, location, channel);
|
||||
|
||||
if (rv <= 0)
|
||||
{
|
||||
printf ("Error returned ms_nslc2sid()\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Original SID: '%s'\n", original_sid);
|
||||
printf (" network: '%s', station: '%s', location: '%s', channel: '%s'\n",
|
||||
network, station, location, channel);
|
||||
printf (" SID: '%s'\n", sid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
char *sid;
|
||||
int idx;
|
||||
|
||||
sid = "FDSN:NET_STA_LOC_C_H_N";
|
||||
|
||||
if (map_sid (sid))
|
||||
{
|
||||
printf ("Error with map_sid()\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Map each value give on the command line */
|
||||
if (argc > 1)
|
||||
{
|
||||
for (idx = 1; idx < argc; idx++)
|
||||
{
|
||||
if (map_sid (argv[idx]))
|
||||
{
|
||||
printf ("Error with map_sid()\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/***************************************************************************
|
||||
* A program illustrating time string parsing and generation support.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <libmseed.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
char *timestr;
|
||||
char generated_timestr[40];
|
||||
nstime_t nstime;
|
||||
int idx;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
ms_log (0, "Usage: %s timestring1 [timestring2] [timestring3] [...]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (idx = 1; idx < argc; idx++)
|
||||
{
|
||||
timestr = argv[idx];
|
||||
|
||||
printf ("Input time : %s\n", timestr);
|
||||
|
||||
/* Convert time string to epoch format */
|
||||
nstime = ms_timestr2nstime (timestr);
|
||||
|
||||
if (nstime == NSTERROR)
|
||||
{
|
||||
ms_log (2, "Cannot convert time string to epoch format: '%s'\n", timestr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Convert epoch time to ISO month-day time string */
|
||||
if (!ms_nstime2timestr (nstime, generated_timestr, ISOMONTHDAY, NANO_MICRO_NONE))
|
||||
{
|
||||
ms_log (2, "Cannot convert epoch to ISOMONTHDAY time string\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf ("ISOMONTH : %s\n", generated_timestr);
|
||||
|
||||
/* Convert epoch time to ISO month-day time string with Z designator */
|
||||
if (!ms_nstime2timestr (nstime, generated_timestr, ISOMONTHDAY_Z, NANO_MICRO_NONE))
|
||||
{
|
||||
ms_log (2, "Cannot convert epoch to ISOMONTHDAY_Z time string\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf ("ISOMONTH_Z : %s\n", generated_timestr);
|
||||
|
||||
/* Convert epoch time to ISO month-day with day-of-year time string */
|
||||
if (!ms_nstime2timestr (nstime, generated_timestr, ISOMONTHDAY_DOY, NANO_MICRO_NONE))
|
||||
{
|
||||
ms_log (2, "Cannot convert epoch to ISOMONTHDAY_DOY time string\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf ("ISOMONTH_DOY : %s\n", generated_timestr);
|
||||
|
||||
/* Convert epoch time to ISO month-day with day-of-year time string with Z designator */
|
||||
if (!ms_nstime2timestr (nstime, generated_timestr, ISOMONTHDAY_DOY_Z, NANO_MICRO_NONE))
|
||||
{
|
||||
ms_log (2, "Cannot convert epoch to ISOMONTHDAY_DOY_Z time string\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf ("ISOMONTH_DOY_Z: %s\n", generated_timestr);
|
||||
|
||||
/* Convert epoch time to SEED-style ordinal (day-of-year) time string */
|
||||
if (!ms_nstime2timestr (nstime, generated_timestr, SEEDORDINAL, NANO_MICRO_NONE))
|
||||
{
|
||||
ms_log (2, "Cannot convert epoch to SEEDORDINAL time string\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf ("SEEDORDINAL : %s\n", generated_timestr);
|
||||
|
||||
/* Convert epoch time to Unix epoch time string */
|
||||
if (!ms_nstime2timestr (nstime, generated_timestr, UNIXEPOCH, NANO_MICRO_NONE))
|
||||
{
|
||||
ms_log (2, "Cannot convert epoch to UNIXEPOCH time string\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf ("UNIXEPOCH : %s\n", generated_timestr);
|
||||
|
||||
/* Convert epoch time to nanosecond epoch time string */
|
||||
if (!ms_nstime2timestr (nstime, generated_timestr, NANOSECONDEPOCH, NANO_MICRO_NONE))
|
||||
{
|
||||
ms_log (2, "Cannot convert epoch to NANOSECONDEPOCH time string\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf ("NSEPOCH : %s\n", generated_timestr);
|
||||
printf ("nstime_t : %" PRId64 "\n\n", nstime);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,235 @@
|
||||
/***************************************************************************
|
||||
* A simple example of using libmseed to read miniSEED.
|
||||
*
|
||||
* Opens a user specified file, parses the miniSEED records and prints
|
||||
* details for each record.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <libmseed.h>
|
||||
|
||||
#define VERSION "[libmseed " LIBMSEED_VERSION " example]"
|
||||
#define PACKAGE "mseedview"
|
||||
|
||||
static int8_t verbose = 0;
|
||||
static int8_t ppackets = 0;
|
||||
static int8_t basicsum = 0;
|
||||
static int printdata = 0;
|
||||
static char *inputfile = NULL;
|
||||
|
||||
static int parameter_proc (int argcount, char **argvec);
|
||||
static void usage (void);
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
MS3Record *msr = NULL;
|
||||
uint32_t flags = 0;
|
||||
|
||||
int64_t totalrecs = 0;
|
||||
int64_t totalsamps = 0;
|
||||
int retcode;
|
||||
|
||||
/* Process command line arguments */
|
||||
if (parameter_proc (argc, argv) < 0)
|
||||
return -1;
|
||||
|
||||
/* Set flag to validate CRCs when reading */
|
||||
flags |= MSF_VALIDATECRC;
|
||||
|
||||
/* Parse byte range from file/URL path name if present */
|
||||
flags |= MSF_PNAMERANGE;
|
||||
|
||||
/* Set flag to unpack data if printing samples */
|
||||
if (printdata)
|
||||
flags |= MSF_UNPACKDATA;
|
||||
|
||||
/* Enable accumulation of up to 10 error and warning messages */
|
||||
ms_rloginit (NULL, NULL, NULL, NULL, 10);
|
||||
|
||||
/* Loop over the input file record by record */
|
||||
while ((retcode = ms3_readmsr (&msr, inputfile, flags, verbose)) == MS_NOERROR)
|
||||
{
|
||||
totalrecs++;
|
||||
totalsamps += msr->samplecnt;
|
||||
|
||||
msr3_print (msr, ppackets);
|
||||
|
||||
/* Print data samples */
|
||||
if (printdata && msr->numsamples > 0)
|
||||
{
|
||||
int line, col, cnt, samplesize;
|
||||
int lines = (msr->numsamples / 6) + 1;
|
||||
void *sptr;
|
||||
|
||||
if ((samplesize = ms_samplesize (msr->sampletype)) == 0)
|
||||
{
|
||||
ms_log (2, "Unrecognized sample type: '%c'\n", msr->sampletype);
|
||||
}
|
||||
|
||||
for (cnt = 0, line = 0; line < lines; line++)
|
||||
{
|
||||
for (col = 0; col < 6; col++)
|
||||
{
|
||||
if (cnt < msr->numsamples)
|
||||
{
|
||||
sptr = (char *)msr->datasamples + (cnt * samplesize);
|
||||
|
||||
if (msr->sampletype == 'i')
|
||||
ms_log (0, "%10d ", *(int32_t *)sptr);
|
||||
|
||||
else if (msr->sampletype == 'f')
|
||||
ms_log (0, "%10.8g ", *(float *)sptr);
|
||||
|
||||
else if (msr->sampletype == 'd')
|
||||
ms_log (0, "%10.10g ", *(double *)sptr);
|
||||
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
ms_log (0, "\n");
|
||||
|
||||
/* If only printing the first 6 samples break out here */
|
||||
if (printdata == 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit all accumulated warning and error messages */
|
||||
ms_rlog_emit (NULL, 0, verbose);
|
||||
|
||||
/* Make sure everything is cleaned up */
|
||||
ms3_readmsr (&msr, NULL, 0, 0);
|
||||
|
||||
if (basicsum)
|
||||
ms_log (0, "Records: %" PRId64 ", Samples: %" PRId64 "\n",
|
||||
totalrecs, totalsamps);
|
||||
|
||||
return 0;
|
||||
} /* End of main() */
|
||||
|
||||
/***************************************************************************
|
||||
* parameter_proc():
|
||||
* Process the command line arguments.
|
||||
*
|
||||
* Returns 0 on success, and -1 on failure
|
||||
***************************************************************************/
|
||||
static int
|
||||
parameter_proc (int argcount, char **argvec)
|
||||
{
|
||||
int optind;
|
||||
|
||||
/* Process all command line arguments */
|
||||
for (optind = 1; optind < argcount; optind++)
|
||||
{
|
||||
if (strcmp (argvec[optind], "-V") == 0)
|
||||
{
|
||||
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
|
||||
exit (0);
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-h") == 0)
|
||||
{
|
||||
usage ();
|
||||
exit (0);
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-v", 2) == 0)
|
||||
{
|
||||
verbose += strspn (&argvec[optind][1], "v");
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-p", 2) == 0)
|
||||
{
|
||||
ppackets += strspn (&argvec[optind][1], "p");
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-d", 2) == 0)
|
||||
{
|
||||
printdata = 1;
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-D", 2) == 0)
|
||||
{
|
||||
printdata = 2;
|
||||
}
|
||||
else if (strcmp (argvec[optind], "-s") == 0)
|
||||
{
|
||||
basicsum = 1;
|
||||
}
|
||||
else if (strncmp (argvec[optind], "-", 1) == 0 &&
|
||||
strlen (argvec[optind]) > 1)
|
||||
{
|
||||
ms_log (2, "Unknown option: %s\n", argvec[optind]);
|
||||
exit (1);
|
||||
}
|
||||
else if (inputfile == NULL)
|
||||
{
|
||||
inputfile = argvec[optind];
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (2, "Unknown option: %s\n", argvec[optind]);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure an input file was specified */
|
||||
if (!inputfile)
|
||||
{
|
||||
ms_log (2, "No input file was specified\n\n");
|
||||
ms_log (1, "%s version %s\n\n", PACKAGE, VERSION);
|
||||
ms_log (1, "Try %s -h for usage\n", PACKAGE);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Add program name and version to User-Agent for URL-based requests */
|
||||
if (libmseed_url_support() && ms3_url_useragent(PACKAGE, VERSION))
|
||||
return -1;
|
||||
|
||||
/* Report the program version */
|
||||
if (verbose)
|
||||
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
|
||||
|
||||
return 0;
|
||||
} /* End of parameter_proc() */
|
||||
|
||||
/***************************************************************************
|
||||
* usage():
|
||||
* Print the usage message and exit.
|
||||
***************************************************************************/
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
fprintf (stderr, "%s version: %s\n\n", PACKAGE, VERSION);
|
||||
fprintf (stderr, "Usage: %s [options] file\n\n", PACKAGE);
|
||||
fprintf (stderr,
|
||||
" ## Options ##\n"
|
||||
" -V Report program version\n"
|
||||
" -h Show this usage message\n"
|
||||
" -v Be more verbose, multiple flags can be used\n"
|
||||
" -p Print details of header, multiple flags can be used\n"
|
||||
" -d Print first 6 sample values\n"
|
||||
" -D Print all sample values\n"
|
||||
" -s Print a basic summary after processing a file\n"
|
||||
"\n"
|
||||
" file File of miniSEED records\n"
|
||||
"\n");
|
||||
} /* End of usage() */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,50 @@
|
||||
/***************************************************************************
|
||||
* Interface declarations for the extra header routines in extraheaders.c
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef EXTRAHEADERS_H
|
||||
#define EXTRAHEADERS_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "libmseed.h"
|
||||
#include "yyjson.h"
|
||||
|
||||
/* Avoid unused parameter warnings in known cases */
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
/* Private allocation wrappers for yyjson's allocator definition */
|
||||
void *_priv_malloc(void *ctx, size_t size);
|
||||
void *_priv_realloc(void *ctx, void *ptr, size_t oldsize, size_t size);
|
||||
void _priv_free(void *ctx, void *ptr);
|
||||
|
||||
/* Internal structure for holding parsed JSON extra headers */
|
||||
struct LM_PARSED_JSON_s
|
||||
{
|
||||
yyjson_doc *doc;
|
||||
yyjson_mut_doc *mut_doc;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,185 @@
|
||||
/***************************************************************************
|
||||
* The contained ms_gmtime64_r() is a 64-bit version of the standard
|
||||
* gmtime_r() and was derived from the y2038 project:
|
||||
* https://github.com/evalEmpire/y2038/
|
||||
*
|
||||
* Original copyright and license are included.
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
|
||||
Copyright (c) 2007-2010 Michael G Schwern
|
||||
|
||||
This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
|
||||
|
||||
The MIT License:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
static const char days_in_month[2][12] = {
|
||||
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
};
|
||||
|
||||
static const short julian_days_by_month[2][12] = {
|
||||
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
|
||||
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
|
||||
};
|
||||
|
||||
static const short length_of_year[2] = {365, 366};
|
||||
|
||||
/* Some numbers relating to the gregorian cycle */
|
||||
static const int64_t years_in_gregorian_cycle = 400;
|
||||
#define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1)
|
||||
|
||||
/* Let's assume people are going to be looking for dates in the future.
|
||||
Let's provide some cheats so you can skip ahead.
|
||||
This has a 4x speed boost when near 2008.
|
||||
*/
|
||||
/* Number of days since epoch on Jan 1st, 2008 GMT */
|
||||
#define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
|
||||
#define CHEAT_YEARS 108
|
||||
|
||||
/* IS_LEAP is used all over the place to index on arrays, so make sure it always returns 0 or 1. */
|
||||
#define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) ? 1 : 0)
|
||||
|
||||
/* Allegedly, some <termios.h> define a macro called WRAP, so use a longer name like WRAP_TIME64. */
|
||||
#define WRAP_TIME64(a, b, m) ((a) = ((a) < 0) ? ((b)--, (a) + (m)) : (a))
|
||||
|
||||
struct tm *
|
||||
ms_gmtime64_r (const int64_t *in_time, struct tm *p)
|
||||
{
|
||||
int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
|
||||
int64_t v_tm_tday;
|
||||
int leap;
|
||||
int64_t m;
|
||||
int64_t time;
|
||||
int64_t year = 70;
|
||||
int64_t cycles = 0;
|
||||
|
||||
if (!in_time || !p)
|
||||
return NULL;
|
||||
|
||||
time = *in_time;
|
||||
|
||||
v_tm_sec = (int)(time % 60);
|
||||
time /= 60;
|
||||
v_tm_min = (int)(time % 60);
|
||||
time /= 60;
|
||||
v_tm_hour = (int)(time % 24);
|
||||
time /= 24;
|
||||
v_tm_tday = time;
|
||||
|
||||
WRAP_TIME64 (v_tm_sec, v_tm_min, 60);
|
||||
WRAP_TIME64 (v_tm_min, v_tm_hour, 60);
|
||||
WRAP_TIME64 (v_tm_hour, v_tm_tday, 24);
|
||||
|
||||
v_tm_wday = (int)((v_tm_tday + 4) % 7);
|
||||
if (v_tm_wday < 0)
|
||||
v_tm_wday += 7;
|
||||
m = v_tm_tday;
|
||||
|
||||
if (m >= CHEAT_DAYS)
|
||||
{
|
||||
year = CHEAT_YEARS;
|
||||
m -= CHEAT_DAYS;
|
||||
}
|
||||
|
||||
if (m >= 0)
|
||||
{
|
||||
/* Gregorian cycles, this is huge optimization for distant times */
|
||||
cycles = m / (int64_t)days_in_gregorian_cycle;
|
||||
if (cycles)
|
||||
{
|
||||
m -= cycles * (int64_t)days_in_gregorian_cycle;
|
||||
year += cycles * years_in_gregorian_cycle;
|
||||
}
|
||||
|
||||
/* Years */
|
||||
leap = IS_LEAP (year);
|
||||
while (m >= (int64_t)length_of_year[leap])
|
||||
{
|
||||
m -= (int64_t)length_of_year[leap];
|
||||
year++;
|
||||
leap = IS_LEAP (year);
|
||||
}
|
||||
|
||||
/* Months */
|
||||
v_tm_mon = 0;
|
||||
while (m >= (int64_t)days_in_month[leap][v_tm_mon])
|
||||
{
|
||||
m -= (int64_t)days_in_month[leap][v_tm_mon];
|
||||
v_tm_mon++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
year--;
|
||||
|
||||
/* Gregorian cycles */
|
||||
cycles = (m / (int64_t)days_in_gregorian_cycle) + 1;
|
||||
if (cycles)
|
||||
{
|
||||
m -= cycles * (int64_t)days_in_gregorian_cycle;
|
||||
year += cycles * years_in_gregorian_cycle;
|
||||
}
|
||||
|
||||
/* Years */
|
||||
leap = IS_LEAP (year);
|
||||
while (m < (int64_t)-length_of_year[leap])
|
||||
{
|
||||
m += (int64_t)length_of_year[leap];
|
||||
year--;
|
||||
leap = IS_LEAP (year);
|
||||
}
|
||||
|
||||
/* Months */
|
||||
v_tm_mon = 11;
|
||||
while (m < (int64_t)-days_in_month[leap][v_tm_mon])
|
||||
{
|
||||
m += (int64_t)days_in_month[leap][v_tm_mon];
|
||||
v_tm_mon--;
|
||||
}
|
||||
m += (int64_t)days_in_month[leap][v_tm_mon];
|
||||
}
|
||||
|
||||
p->tm_year = (int)year;
|
||||
|
||||
if (p->tm_year != year)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* At this point m is less than a year so casting to an int is safe */
|
||||
p->tm_mday = (int)m + 1;
|
||||
p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m;
|
||||
p->tm_sec = v_tm_sec;
|
||||
p->tm_min = v_tm_min;
|
||||
p->tm_hour = v_tm_hour;
|
||||
p->tm_mon = v_tm_mon;
|
||||
p->tm_wday = v_tm_wday;
|
||||
|
||||
return p;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/***************************************************************************
|
||||
* Interface declaration for function in gmtime64.c.
|
||||
*
|
||||
* See gmtime.c for copyright and license.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef GMTIME64_H
|
||||
#define GMTIME64_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "libmseed.h"
|
||||
|
||||
extern struct tm * ms_gmtime64_r (const int64_t *in_time, struct tm *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,100 @@
|
||||
LIBRARY libmseed.dll
|
||||
EXPORTS
|
||||
ms_nstime2time
|
||||
ms_nstime2timestr
|
||||
ms_nstime2timestrz
|
||||
ms_time2nstime
|
||||
ms_timestr2nstime
|
||||
ms_mdtimestr2nstime
|
||||
ms_seedtimestr2nstime
|
||||
ms_doy2md
|
||||
ms_md2doy
|
||||
msr3_parse
|
||||
msr3_pack
|
||||
msr3_repack_mseed3
|
||||
msr3_pack_header3
|
||||
msr3_pack_header2
|
||||
msr3_unpack_data
|
||||
msr3_data_bounds
|
||||
ms_decode_data
|
||||
msr3_init
|
||||
msr3_free
|
||||
msr3_duplicate
|
||||
msr3_endtime
|
||||
msr3_print
|
||||
msr3_resize_buffer
|
||||
msr3_sampratehz
|
||||
msr3_host_latency
|
||||
ms3_detect
|
||||
ms_parse_raw3
|
||||
ms_parse_raw2
|
||||
ms3_matchselect
|
||||
msr3_matchselect
|
||||
ms3_addselect
|
||||
ms3_addselect_comp
|
||||
ms3_readselectionsfile
|
||||
ms3_freeselections
|
||||
ms3_printselections
|
||||
mstl3_init
|
||||
mstl3_free
|
||||
mstl3_findID
|
||||
mstl3_addmsr_recordptr
|
||||
mstl3_readbuffer
|
||||
mstl3_readbuffer_selection
|
||||
mstl3_unpack_recordlist
|
||||
mstl3_convertsamples
|
||||
mstl3_resize_buffers
|
||||
mstl3_pack
|
||||
mstl3_printtracelist
|
||||
mstl3_printsynclist
|
||||
mstl3_printgaplist
|
||||
ms3_readmsr
|
||||
ms3_readmsr_r
|
||||
ms3_readmsr_selection
|
||||
ms3_readtracelist
|
||||
ms3_readtracelist_timewin
|
||||
ms3_readtracelist_selection
|
||||
ms3_url_useragent
|
||||
ms3_url_userpassword
|
||||
ms3_url_addheader
|
||||
ms3_url_freeheaders
|
||||
msr3_writemseed
|
||||
mstl3_writemseed
|
||||
libmseed_url_support
|
||||
ms_sid2nslc
|
||||
ms_nslc2sid
|
||||
ms_seedchan2xchan
|
||||
ms_xchan2seedchan
|
||||
ms_strncpclean
|
||||
ms_strncpcleantail
|
||||
ms_strncpopen
|
||||
mseh_get_ptr_r
|
||||
mseh_set_ptr_r
|
||||
mseh_add_event_detection_r
|
||||
mseh_add_calibration_r
|
||||
mseh_add_timing_exception_r
|
||||
mseh_add_recenter_r
|
||||
mseh_serialize
|
||||
mseh_free_parsestate
|
||||
mseh_print
|
||||
ms_rlog
|
||||
ms_rlog_l
|
||||
ms_rloginit
|
||||
ms_rloginit_l
|
||||
ms_rlog_emit
|
||||
ms_rlog_free
|
||||
ms_readleapseconds
|
||||
ms_readleapsecondfile
|
||||
ms_samplesize
|
||||
ms_encoding_sizetype
|
||||
ms_encodingstr
|
||||
ms_errorstr
|
||||
ms_sampletime
|
||||
ms_dabs
|
||||
ms_bigendianhost
|
||||
ms_crc32c
|
||||
ms_gswap2
|
||||
ms_gswap4
|
||||
ms_gswap8
|
||||
leapsecondlist
|
||||
libmseed_memory
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -0,0 +1,13 @@
|
||||
{
|
||||
global:
|
||||
ms_*;
|
||||
ms3_*;
|
||||
msr_*;
|
||||
msr3_*;
|
||||
mstl3_*;
|
||||
mseh_*;
|
||||
leapsecondlist;
|
||||
libmseed_memory;
|
||||
local:
|
||||
*;
|
||||
};
|
@ -0,0 +1,657 @@
|
||||
/***************************************************************************
|
||||
* Common logging facility.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libmseed.h"
|
||||
|
||||
void rloginit_int (MSLogParam *logp,
|
||||
void (*log_print) (const char *), const char *logprefix,
|
||||
void (*diag_print) (const char *), const char *errprefix,
|
||||
int maxmessages);
|
||||
|
||||
int rlog_int (MSLogParam *logp, const char *function, int level,
|
||||
const char *format, va_list *varlist);
|
||||
|
||||
int add_message_int (MSLogRegistry *logreg, const char *function, int level,
|
||||
const char *message);
|
||||
void print_message_int (MSLogParam *logp, int level, const char *message,
|
||||
char *terminator);
|
||||
|
||||
/* Initialize the global logging parameters
|
||||
*
|
||||
* If not disabled by a defined LIBMSEED_NO_THREADING, use options for
|
||||
* thread-local storage. In this default case each thread will have
|
||||
* it's own "global" logging parameters initialized to the library
|
||||
* default settings.
|
||||
*
|
||||
* Windows has its own designation for TLS.
|
||||
* Otherwise, C11 defines the standardized _Thread_local storage-class.
|
||||
* Otherwise fallback to the commonly supported __thread keyword.
|
||||
*/
|
||||
#if !defined(LIBMSEED_NO_THREADING)
|
||||
#if defined(LMP_WIN)
|
||||
#define lm_thread_local __declspec( thread )
|
||||
#elif __STDC_VERSION__ >= 201112L
|
||||
#define lm_thread_local _Thread_local
|
||||
#else
|
||||
#define lm_thread_local __thread
|
||||
#endif
|
||||
lm_thread_local MSLogParam gMSLogParam = MSLogParam_INITIALIZER;
|
||||
#else
|
||||
MSLogParam gMSLogParam = MSLogParam_INITIALIZER;
|
||||
#endif
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Initialize the global logging parameters.
|
||||
*
|
||||
* Any message printing functions indicated must except a single
|
||||
* argument, namely a string \c (const char *) that will contain the log
|
||||
* message. If the function pointers are NULL, defaults will be used.
|
||||
*
|
||||
* If the log and error prefixes have been set they will be pre-pended
|
||||
* to the message. If the prefixes are NULL, defaults will be used.
|
||||
*
|
||||
* If \a maxmessages is greater than zero, warning and error (level >=
|
||||
* 1) messages will be accumulated in a message registry. Once the
|
||||
* maximum number of messages have accumulated, the oldest messages
|
||||
* are discarded. Messages in the registry can be printed using
|
||||
* ms_rlog_emit() or cleared using ms_rlog_free().
|
||||
*
|
||||
* @param[in] log_print Function to print log messages
|
||||
* @param[in] logprefix Prefix to add to log and diagnostic messages
|
||||
* @param[in] diag_print Function to print diagnostic and error messages
|
||||
* @param[in] errprefix Prefix to add to error messages
|
||||
* @param[in] maxmessages Maximum number of error/warning messages to store in registry
|
||||
*
|
||||
* \sa ms_rlog()
|
||||
* \sa ms_rlog_emit()
|
||||
* \sa ms_rlog_free()
|
||||
***************************************************************************/
|
||||
void
|
||||
ms_rloginit (void (*log_print) (const char *), const char *logprefix,
|
||||
void (*diag_print) (const char *), const char *errprefix,
|
||||
int maxmessages)
|
||||
{
|
||||
rloginit_int (&gMSLogParam, log_print, logprefix,
|
||||
diag_print, errprefix, maxmessages);
|
||||
} /* End of ms_rloginit() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Initialize specified ::MSLogParam logging parameters.
|
||||
*
|
||||
* If the logging parameters have not been initialized (logp == NULL),
|
||||
* new parameter space will be allocated.
|
||||
*
|
||||
* Any message printing functions indicated must except a single
|
||||
* argument, namely a string \c (const char *) that will contain the log
|
||||
* message. If the function pointers are NULL, defaults will be used.
|
||||
*
|
||||
* If the log and error prefixes have been set they will be pre-pended
|
||||
* to the message. If the prefixes are NULL, defaults will be used.
|
||||
*
|
||||
* If \a maxmessages is greater than zero, warning and error (level >=
|
||||
* 1) messages will be accumulated in a message registry. Once the
|
||||
* maximum number of messages have accumulated, the oldest messages
|
||||
* are discarded. Messages in the registry can be printed using
|
||||
* ms_rlog_emit() or cleared using ms_rlog_free().
|
||||
*
|
||||
* @param[in] logp ::MSLogParam logging parameters
|
||||
* @param[in] log_print Function to print log messages
|
||||
* @param[in] logprefix Prefix to add to log and diagnostic messages
|
||||
* @param[in] diag_print Function to print diagnostic and error messages
|
||||
* @param[in] errprefix Prefix to add to error messages
|
||||
* @param[in] maxmessages Maximum number of error/warning messages to store in registry
|
||||
*
|
||||
* @returns a pointer to the created/re-initialized MSLogParam struct
|
||||
* on success and NULL on error.
|
||||
*
|
||||
* \sa ms_rlog()
|
||||
* \sa ms_rlog_emit()
|
||||
* \sa ms_rlog_free()
|
||||
***************************************************************************/
|
||||
MSLogParam *
|
||||
ms_rloginit_l (MSLogParam *logp,
|
||||
void (*log_print) (const char *), const char *logprefix,
|
||||
void (*diag_print) (const char *), const char *errprefix,
|
||||
int maxmessages)
|
||||
{
|
||||
MSLogParam *llog;
|
||||
|
||||
if (logp == NULL)
|
||||
{
|
||||
llog = (MSLogParam *)libmseed_memory.malloc (sizeof (MSLogParam));
|
||||
|
||||
if (llog == NULL)
|
||||
{
|
||||
ms_log (2, "Cannot allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
llog->log_print = NULL;
|
||||
llog->logprefix = NULL;
|
||||
llog->diag_print = NULL;
|
||||
llog->errprefix = NULL;
|
||||
llog->registry.maxmessages = 0;
|
||||
llog->registry.messagecnt = 0;
|
||||
llog->registry.messages = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
llog = logp;
|
||||
}
|
||||
|
||||
rloginit_int (llog, log_print, logprefix,
|
||||
diag_print, errprefix, maxmessages);
|
||||
|
||||
return llog;
|
||||
} /* End of ms_rloginit_l() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Initialize the logging subsystem.
|
||||
*
|
||||
* This function modifies the logging parameters in the supplied
|
||||
* ::MSLogParam. Use NULL for the function pointers or the prefixes if
|
||||
* they should not be changed from previously set or default values.
|
||||
*
|
||||
***************************************************************************/
|
||||
void
|
||||
rloginit_int (MSLogParam *logp,
|
||||
void (*log_print) (const char *), const char *logprefix,
|
||||
void (*diag_print) (const char *), const char *errprefix,
|
||||
int maxmessages)
|
||||
{
|
||||
if (!logp)
|
||||
return;
|
||||
|
||||
if (log_print)
|
||||
logp->log_print = log_print;
|
||||
|
||||
if (logprefix)
|
||||
{
|
||||
if (strlen (logprefix) >= MAX_LOG_MSG_LENGTH)
|
||||
{
|
||||
ms_log_l (logp, 2, "%s", "log message prefix is too large");
|
||||
}
|
||||
else
|
||||
{
|
||||
logp->logprefix = logprefix;
|
||||
}
|
||||
}
|
||||
|
||||
if (diag_print)
|
||||
logp->diag_print = diag_print;
|
||||
|
||||
if (errprefix)
|
||||
{
|
||||
if (strlen (errprefix) >= MAX_LOG_MSG_LENGTH)
|
||||
{
|
||||
ms_log_l (logp, 2, "%s", "error message prefix is too large");
|
||||
}
|
||||
else
|
||||
{
|
||||
logp->errprefix = errprefix;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxmessages >= 0)
|
||||
{
|
||||
logp->registry.maxmessages = maxmessages;
|
||||
}
|
||||
|
||||
return;
|
||||
} /* End of rloginit_int() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Register log message using global logging parameters.
|
||||
*
|
||||
* It is convenient to call this function via the ms_log() macro,
|
||||
* which sets the calling function automatically.
|
||||
*
|
||||
* Three message levels are recognized, see @ref logging-levels for
|
||||
* more information.
|
||||
*
|
||||
* This function builds the log/error message and passes to it to the
|
||||
* appropriate print function. If custom printing functions have not
|
||||
* been defined, messages will be printed with \c fprintf(), log
|
||||
* messages to \c stdout and error messages to \c stderr.
|
||||
*
|
||||
* If the log/error prefixes have been set they will be pre-pended to
|
||||
* the message. If no custom log prefix is set none will be included.
|
||||
* If no custom error prefix is set \c "Error: " will be included.
|
||||
*
|
||||
* A trailing newline character is for error messages is removed if
|
||||
* the message is added to the log registry.
|
||||
*
|
||||
* All messages will be truncated at the ::MAX_LOG_MSG_LENGTH, this
|
||||
* includes any prefix.
|
||||
*
|
||||
* @param[in] function Name of function registering log message
|
||||
* @param[in] level Message level
|
||||
* @param[in] format Message format in printf() style
|
||||
* @param[in] ... Message format variables
|
||||
*
|
||||
* @returns The number of characters formatted on success, and a
|
||||
* negative value on error..
|
||||
***************************************************************************/
|
||||
int
|
||||
ms_rlog (const char *function, int level, const char *format, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list varlist;
|
||||
|
||||
va_start (varlist, format);
|
||||
|
||||
retval = rlog_int (&gMSLogParam, function, level, format, &varlist);
|
||||
|
||||
va_end (varlist);
|
||||
|
||||
return retval;
|
||||
} /* End of ms_rlog() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Register log message using specified logging parameters.
|
||||
*
|
||||
* It is convenient to call this function via the ms_log_l() macro,
|
||||
* which sets the calling function automatically.
|
||||
*
|
||||
* The function uses logging parameters specified in the supplied
|
||||
* ::MSLogParam. This reentrant capability allows using different
|
||||
* parameters in different parts of a program or different threads.
|
||||
*
|
||||
* Three message levels are recognized, see @ref logging-levels for
|
||||
* more information.
|
||||
*
|
||||
* This function builds the log/error message and passes to it to the
|
||||
* appropriate print function. If custom printing functions have not
|
||||
* been defined, messages will be printed with \c fprintf(), log
|
||||
* messages to \c stdout and error messages to \c stderr.
|
||||
*
|
||||
* If the log/error prefixes have been set they will be pre-pended to
|
||||
* the message. If no custom log prefix is set none will be included.
|
||||
* If no custom error prefix is set \c "Error: " will be included.
|
||||
*
|
||||
* A trailing newline character is for error messages is removed if
|
||||
* the message is added to the log registry.
|
||||
*
|
||||
* All messages will be truncated at the ::MAX_LOG_MSG_LENGTH, this
|
||||
* includes any prefix.
|
||||
*
|
||||
* @param[in] logp Pointer to ::MSLogParam to use for this message
|
||||
* @param[in] function Name of function registering log message
|
||||
* @param[in] level Message level
|
||||
* @param[in] format Message format in printf() style
|
||||
* @param[in] ... Message format variables
|
||||
*
|
||||
* @returns The number of characters formatted on success, and a
|
||||
* negative value on error.
|
||||
***************************************************************************/
|
||||
int
|
||||
ms_rlog_l (MSLogParam *logp, const char *function, int level, const char *format, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list varlist;
|
||||
|
||||
if (!logp)
|
||||
logp = &gMSLogParam;
|
||||
|
||||
va_start (varlist, format);
|
||||
|
||||
retval = rlog_int (logp, function, level, format, &varlist);
|
||||
|
||||
va_end (varlist);
|
||||
|
||||
return retval;
|
||||
} /* End of ms_rlog_l() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Log message using specified logging parameters and \c va_list
|
||||
*
|
||||
* Trailing newline character is removed when added messages to the
|
||||
* registry.
|
||||
*
|
||||
* @param[in] logp Pointer to ::MSLogParam to use for this message
|
||||
* @param[in] function Name of function registering log message
|
||||
* @param[in] level Message level
|
||||
* @param[in] varlist Message in a \c va_list in printf() style
|
||||
*
|
||||
* @returns The number of characters formatted on success, and a
|
||||
* negative value on error.
|
||||
***************************************************************************/
|
||||
int
|
||||
rlog_int (MSLogParam *logp, const char *function, int level,
|
||||
const char *format, va_list *varlist)
|
||||
{
|
||||
char message[MAX_LOG_MSG_LENGTH];
|
||||
int presize = 0;
|
||||
int printed = 0;
|
||||
|
||||
if (!logp)
|
||||
{
|
||||
fprintf (stderr, "%s() called without specifying log parameters", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
message[0] = '\0';
|
||||
|
||||
if (level >= 2) /* Error message */
|
||||
{
|
||||
if (logp->errprefix != NULL)
|
||||
{
|
||||
strncpy (message, logp->errprefix, MAX_LOG_MSG_LENGTH);
|
||||
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy (message, "Error: ", MAX_LOG_MSG_LENGTH);
|
||||
}
|
||||
|
||||
presize = strlen (message);
|
||||
printed = vsnprintf (&message[presize],
|
||||
MAX_LOG_MSG_LENGTH - presize,
|
||||
format, *varlist);
|
||||
|
||||
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
|
||||
}
|
||||
else if (level == 1) /* Diagnostic message */
|
||||
{
|
||||
if (logp->logprefix != NULL)
|
||||
{
|
||||
strncpy (message, logp->logprefix, MAX_LOG_MSG_LENGTH);
|
||||
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
|
||||
}
|
||||
|
||||
presize = strlen (message);
|
||||
printed = vsnprintf (&message[presize],
|
||||
MAX_LOG_MSG_LENGTH - presize,
|
||||
format, *varlist);
|
||||
|
||||
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
|
||||
}
|
||||
else if (level == 0) /* Normal log message */
|
||||
{
|
||||
if (logp->logprefix != NULL)
|
||||
{
|
||||
strncpy (message, logp->logprefix, MAX_LOG_MSG_LENGTH);
|
||||
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
|
||||
}
|
||||
|
||||
presize = strlen (message);
|
||||
printed = vsnprintf (&message[presize],
|
||||
MAX_LOG_MSG_LENGTH - presize,
|
||||
format, *varlist);
|
||||
|
||||
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
|
||||
}
|
||||
|
||||
printed += presize;
|
||||
|
||||
/* Add warning/error message to registry if enabled */
|
||||
if (level >= 1 && logp->registry.maxmessages > 0)
|
||||
{
|
||||
/* Remove trailing newline if present */
|
||||
if (message[printed - 1] == '\n')
|
||||
{
|
||||
message[printed - 1] = '\0';
|
||||
printed -= 1;
|
||||
}
|
||||
|
||||
add_message_int (&logp->registry, function, level, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
print_message_int (logp, level, message, NULL);
|
||||
}
|
||||
|
||||
return printed;
|
||||
} /* End of rlog_int() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Add message to registry
|
||||
*
|
||||
* Add a message to the specified log registry. Earliest entries are
|
||||
* removed to remain within the specified maximum number of messsages.
|
||||
*
|
||||
* @param[in] logreg Pointer to ::MSLogRegistry to use for this message
|
||||
* @param[in] function Name of function generating the message
|
||||
* @param[in] level Message level
|
||||
* @param[in] message Message text
|
||||
*
|
||||
* @returns Zero on sucess and non-zero on error
|
||||
***************************************************************************/
|
||||
int
|
||||
add_message_int (MSLogRegistry *logreg, const char *function, int level,
|
||||
const char *message)
|
||||
{
|
||||
MSLogEntry *logentry = NULL;
|
||||
MSLogEntry *lognext = NULL;
|
||||
int count;
|
||||
|
||||
if (!logreg || !message)
|
||||
return -1;
|
||||
|
||||
/* Allocate new entry */
|
||||
logentry = (MSLogEntry *)libmseed_memory.malloc (sizeof (MSLogEntry));
|
||||
|
||||
if (logentry == NULL)
|
||||
{
|
||||
fprintf (stderr, "%s(): Cannot allocate memory for log message\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Populate new entry */
|
||||
logentry->level = level;
|
||||
if (function)
|
||||
{
|
||||
strncpy (logentry->function, function, sizeof (logentry->function));
|
||||
logentry->function[sizeof (logentry->function) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
logentry->function[0] = '\0';
|
||||
}
|
||||
strncpy (logentry->message, message, sizeof (logentry->message));
|
||||
logentry->message[sizeof (logentry->message) - 1] = '\0';
|
||||
|
||||
/* Add entry to registry */
|
||||
logentry->next = logreg->messages;
|
||||
logreg->messages = logentry;
|
||||
logreg->messagecnt += 1;
|
||||
|
||||
/* Remove earliest messages if more than maximum allowed */
|
||||
if (logreg->messagecnt > logreg->maxmessages)
|
||||
{
|
||||
count = 0;
|
||||
logentry = logreg->messages;
|
||||
while (logentry)
|
||||
{
|
||||
lognext = logentry->next;
|
||||
count++;
|
||||
|
||||
if (count == logreg->maxmessages)
|
||||
logentry->next = NULL;
|
||||
|
||||
if (count > logreg->maxmessages)
|
||||
free (logentry);
|
||||
|
||||
logentry = lognext;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* End of add_message_int() */
|
||||
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Send message to print functions
|
||||
*
|
||||
* @param[in] logp Pointer to ::MSLogParam appropriate for this message
|
||||
* @param[in] level Message level
|
||||
* @param[in] message Message to print
|
||||
*
|
||||
* @returns Zero on success, and a negative value on error.
|
||||
***************************************************************************/
|
||||
void
|
||||
print_message_int (MSLogParam *logp, int level, const char *message,
|
||||
char *terminator)
|
||||
{
|
||||
if (!logp || !message)
|
||||
return;
|
||||
|
||||
if (level >= 1) /* Error or warning message */
|
||||
{
|
||||
if (logp->diag_print != NULL)
|
||||
{
|
||||
logp->diag_print (message);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s%s", message, (terminator) ? terminator : "");
|
||||
}
|
||||
}
|
||||
else if (level == 0) /* Normal log message */
|
||||
{
|
||||
if (logp->log_print != NULL)
|
||||
{
|
||||
logp->log_print (message);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stdout, "%s%s", message, (terminator) ? terminator : "");
|
||||
}
|
||||
}
|
||||
} /* End of print_message_int() */
|
||||
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Emit, aka send to print functions, messages from log registry
|
||||
*
|
||||
* Emit messages from the log registry, using the printing functions
|
||||
* identified by the ::MSLogParam.
|
||||
*
|
||||
* Messages are printed in order from earliest to latest.
|
||||
*
|
||||
* The maximum number messages to emit, from most recent to earliest,
|
||||
* can be limited using \a count. If the value is 0 all messages are
|
||||
* emitted. If this limit is used and messages are left in the
|
||||
* registry, it is highly recommended to either emit them soon or
|
||||
* clear them with ms_rlog_free(). A common pattern would be to emit
|
||||
* the last message (e.g. \a count of 1) and immediately free
|
||||
* (discard) any remaining messages.
|
||||
*
|
||||
* @param[in] logp ::MSLogParam for this message or NULL for global parameters
|
||||
* @param[in] count Number of messages to emit, 0 to emit all messages
|
||||
* @param[in] context If non-zero include context by prefixing the function name (if available)
|
||||
*
|
||||
* @returns The number of message emitted on success, and a negative
|
||||
* value on error.
|
||||
*
|
||||
* \sa ms_rloginit()
|
||||
* \sa ms_rlog_free()
|
||||
***************************************************************************/
|
||||
int
|
||||
ms_rlog_emit (MSLogParam *logp, int count, int context)
|
||||
{
|
||||
MSLogEntry *logentry = NULL;
|
||||
MSLogEntry *logprint = NULL;
|
||||
char local_message[MAX_LOG_MSG_LENGTH];
|
||||
char *message = NULL;
|
||||
int emit = (count > 0) ? count : -1;
|
||||
|
||||
if (!logp)
|
||||
logp = &gMSLogParam;
|
||||
|
||||
/* Pop off count entries (or all if count <= 0), and invert into print list */
|
||||
logentry = logp->registry.messages;
|
||||
while (logentry && emit)
|
||||
{
|
||||
logp->registry.messages = logentry->next;
|
||||
|
||||
logentry->next = logprint;
|
||||
logprint = logentry;
|
||||
|
||||
if (emit > 0)
|
||||
emit--;
|
||||
|
||||
logentry = logp->registry.messages;
|
||||
}
|
||||
|
||||
/* Print and free entries */
|
||||
logentry = logprint;
|
||||
while (logprint)
|
||||
{
|
||||
/* Add function name to message if requested and present */
|
||||
if (context && logprint->function[0] != '\0')
|
||||
{
|
||||
snprintf (local_message, sizeof(local_message), "%s() %.*s",
|
||||
logprint->function,
|
||||
(int)(MAX_LOG_MSG_LENGTH - sizeof(logprint->function) - 3),
|
||||
logprint->message);
|
||||
message = local_message;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = logprint->message;
|
||||
}
|
||||
|
||||
print_message_int (logp, logprint->level, message, "\n");
|
||||
|
||||
logentry = logprint->next;
|
||||
free (logprint);
|
||||
logprint = logentry;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* End of ms_rlog_emit() */
|
||||
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Free, without emitting, all messages from log registry
|
||||
*
|
||||
* @param[in] logp ::MSLogParam for this message or NULL for global parameters
|
||||
*
|
||||
* @returns The number of message freed on success, and a negative
|
||||
* value on error.
|
||||
***************************************************************************/
|
||||
int
|
||||
ms_rlog_free (MSLogParam *logp)
|
||||
{
|
||||
MSLogEntry *logentry = NULL;
|
||||
int freed = 0;
|
||||
|
||||
if (!logp)
|
||||
logp = &gMSLogParam;
|
||||
|
||||
logentry = logp->registry.messages;
|
||||
|
||||
while (logentry)
|
||||
{
|
||||
freed++;
|
||||
|
||||
logp->registry.messages = logentry->next;
|
||||
free (logentry);
|
||||
logentry = logp->registry.messages;
|
||||
}
|
||||
|
||||
return freed;
|
||||
} /* End of ms_rlog_free() */
|
@ -0,0 +1,239 @@
|
||||
/***************************************************************************
|
||||
* Generic lookup routines for miniSEED information.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "libmseed.h"
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Determine data sample size for each type
|
||||
*
|
||||
* @param[in] sampletype Library sample type code:
|
||||
* @parblock
|
||||
* - \c 't' - Text data type
|
||||
* - \c 'i' - 32-bit integer data type
|
||||
* - \c 'f' - 32-bit float data type
|
||||
* - \c 'd' - 64-bit float (double) data type
|
||||
* @endparblock
|
||||
*
|
||||
* @returns The sample size based on type code or 0 for unknown.
|
||||
***************************************************************************/
|
||||
uint8_t
|
||||
ms_samplesize (char sampletype)
|
||||
{
|
||||
switch (sampletype)
|
||||
{
|
||||
case 't':
|
||||
case 'a':
|
||||
return 1;
|
||||
break;
|
||||
case 'i':
|
||||
case 'f':
|
||||
return 4;
|
||||
break;
|
||||
case 'd':
|
||||
return 8;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
} /* End of ms_samplesize() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Return sample size and/or type for given encoding value
|
||||
*
|
||||
* Determine the decoded sample size and/or type based on data
|
||||
* encoding. The \a samplesize and \a sampletype values will only be
|
||||
* set if not NULL, allowing lookup of either value or both.
|
||||
*
|
||||
* @param[in] encoding Data sample encoding code
|
||||
* @param[out] samplesize Size of sample, pointer that will be set
|
||||
* @param[out] sampletype Sample type, pointer to \c char that will be set
|
||||
*
|
||||
* @returns 0 on success, -1 on error
|
||||
***************************************************************************/
|
||||
int
|
||||
ms_encoding_sizetype (uint8_t encoding, uint8_t *samplesize, char *sampletype)
|
||||
{
|
||||
switch (encoding)
|
||||
{
|
||||
case DE_TEXT:
|
||||
if (samplesize)
|
||||
*samplesize = 1;
|
||||
if (sampletype)
|
||||
*sampletype = 't';
|
||||
break;
|
||||
case DE_INT16:
|
||||
case DE_INT32:
|
||||
case DE_STEIM1:
|
||||
case DE_STEIM2:
|
||||
case DE_CDSN:
|
||||
case DE_SRO:
|
||||
case DE_DWWSSN:
|
||||
if (samplesize)
|
||||
*samplesize = 4;
|
||||
if (sampletype)
|
||||
*sampletype = 'i';
|
||||
break;
|
||||
case DE_FLOAT32:
|
||||
case DE_GEOSCOPE24:
|
||||
case DE_GEOSCOPE163:
|
||||
case DE_GEOSCOPE164:
|
||||
if (samplesize)
|
||||
*samplesize = 4;
|
||||
if (sampletype)
|
||||
*sampletype = 'f';
|
||||
break;
|
||||
case DE_FLOAT64:
|
||||
if (samplesize)
|
||||
*samplesize = 8;
|
||||
if (sampletype)
|
||||
*sampletype = 'd';
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* End of ms_encodingstr_sizetype() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Descriptive string for data encodings
|
||||
*
|
||||
* @param[in] encoding Data sample encoding code
|
||||
*
|
||||
* @returns a string describing a data encoding format
|
||||
***************************************************************************/
|
||||
const char *
|
||||
ms_encodingstr (uint8_t encoding)
|
||||
{
|
||||
switch (encoding)
|
||||
{
|
||||
case 0:
|
||||
return "Text";
|
||||
break;
|
||||
case 1:
|
||||
return "16-bit integer";
|
||||
break;
|
||||
case 2:
|
||||
return "24-bit integer";
|
||||
break;
|
||||
case 3:
|
||||
return "32-bit integer";
|
||||
break;
|
||||
case 4:
|
||||
return "32-bit float (IEEE single)";
|
||||
break;
|
||||
case 5:
|
||||
return "64-bit float (IEEE double)";
|
||||
break;
|
||||
case 10:
|
||||
return "STEIM-1 integer compression";
|
||||
break;
|
||||
case 11:
|
||||
return "STEIM-2 integer compression";
|
||||
break;
|
||||
case 12:
|
||||
return "GEOSCOPE Muxed 24-bit integer";
|
||||
break;
|
||||
case 13:
|
||||
return "GEOSCOPE Muxed 16/3-bit gain/exp";
|
||||
break;
|
||||
case 14:
|
||||
return "GEOSCOPE Muxed 16/4-bit gain/exp";
|
||||
break;
|
||||
case 15:
|
||||
return "US National Network compression";
|
||||
break;
|
||||
case 16:
|
||||
return "CDSN 16-bit gain ranged";
|
||||
break;
|
||||
case 17:
|
||||
return "Graefenberg 16-bit gain ranged";
|
||||
break;
|
||||
case 18:
|
||||
return "IPG - Strasbourg 16-bit gain";
|
||||
break;
|
||||
case 19:
|
||||
return "STEIM-3 integer compression";
|
||||
break;
|
||||
case 30:
|
||||
return "SRO gain ranged";
|
||||
break;
|
||||
case 31:
|
||||
return "HGLP";
|
||||
break;
|
||||
case 32:
|
||||
return "DWWSSN";
|
||||
break;
|
||||
case 33:
|
||||
return "RSTN 16 bit gain ranged";
|
||||
break;
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
} /* End of ms_encodingstr() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Descriptive string for library @ref return-values
|
||||
*
|
||||
* @param[in] errorcode Library error code
|
||||
*
|
||||
* @returns a string describing the library error code or NULL if the
|
||||
* code is unknown.
|
||||
***************************************************************************/
|
||||
const char *
|
||||
ms_errorstr (int errorcode)
|
||||
{
|
||||
switch (errorcode)
|
||||
{
|
||||
case MS_ENDOFFILE:
|
||||
return "End of file reached";
|
||||
break;
|
||||
case MS_NOERROR:
|
||||
return "No error";
|
||||
break;
|
||||
case MS_GENERROR:
|
||||
return "Generic error";
|
||||
break;
|
||||
case MS_NOTSEED:
|
||||
return "No miniSEED data detected";
|
||||
break;
|
||||
case MS_WRONGLENGTH:
|
||||
return "Length of data read does not match record length";
|
||||
break;
|
||||
case MS_OUTOFRANGE:
|
||||
return "SEED record length out of range";
|
||||
break;
|
||||
case MS_UNKNOWNFORMAT:
|
||||
return "Unknown data encoding format";
|
||||
break;
|
||||
case MS_STBADCOMPFLAG:
|
||||
return "Bad Steim compression flag(s) detected";
|
||||
break;
|
||||
case MS_INVALIDCRC:
|
||||
return "Invalid CRC detected";
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} /* End of ms_errorstr() */
|
@ -0,0 +1,11 @@
|
||||
prefix=@PREFIX@
|
||||
exec_prefix=@EXEC_PREFIX@
|
||||
libdir=@LIBDIR@
|
||||
includedir=@INCLUDEDIR@
|
||||
|
||||
Name: libmseed
|
||||
Description: Read and write miniSEED data records (seismological format)
|
||||
URL: https://earthscope.github.io/libmseed/
|
||||
Version: @VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lmseed
|
@ -0,0 +1,658 @@
|
||||
/***************************************************************************
|
||||
* Documentation and helpers for miniSEED structures.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MSEEDFORMAT_H
|
||||
#define MSEEDFORMAT_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "libmseed.h"
|
||||
|
||||
/* Length of Fixed Section of Data Header for miniSEED 3 */
|
||||
#define MS3FSDH_LENGTH 40
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 3.0 Fixed Section of Data Header
|
||||
* 40 bytes, plus length of identifier, plus length of extra headers
|
||||
*
|
||||
* # FIELD TYPE OFFSET
|
||||
* 1 record indicator char[2] 0
|
||||
* 2 format version uint8_t 2
|
||||
* 3 flags uint8_t 3
|
||||
* 4a nanosecond uint32_t 4
|
||||
* 4b year uint16_t 8
|
||||
* 4c day uint16_t 10
|
||||
* 4d hour uint8_t 12
|
||||
* 4e min uint8_t 13
|
||||
* 4f sec uint8_t 14
|
||||
* 5 data encoding uint8_t 15
|
||||
* 6 sample rate/period float64 16
|
||||
* 7 number of samples uint32_t 24
|
||||
* 8 CRC of record uint32_t 28
|
||||
* 9 publication version uint8_t 32
|
||||
* 10 length of identifer uint8_t 33
|
||||
* 11 length of extra headers uint16_t 34
|
||||
* 12 length of data payload uint32_t 36
|
||||
* 13 source identifier char 40
|
||||
* 14 extra headers char 40 + field 10
|
||||
* 15 data payload encoded 40 + field 10 + field 11
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS3FSDH_INDICATOR(record) ((char*)record)
|
||||
#define pMS3FSDH_FORMATVERSION(record) ((uint8_t*)((uint8_t*)record+2))
|
||||
#define pMS3FSDH_FLAGS(record) ((uint8_t*)((uint8_t*)record+3))
|
||||
#define pMS3FSDH_NSEC(record) ((uint32_t*)((uint8_t*)record+4))
|
||||
#define pMS3FSDH_YEAR(record) ((uint16_t*)((uint8_t*)record+8))
|
||||
#define pMS3FSDH_DAY(record) ((uint16_t*)((uint8_t*)record+10))
|
||||
#define pMS3FSDH_HOUR(record) ((uint8_t*)((uint8_t*)record+12))
|
||||
#define pMS3FSDH_MIN(record) ((uint8_t*)((uint8_t*)record+13))
|
||||
#define pMS3FSDH_SEC(record) ((uint8_t*)((uint8_t*)record+14))
|
||||
#define pMS3FSDH_ENCODING(record) ((uint8_t*)((uint8_t*)record+15))
|
||||
#define pMS3FSDH_SAMPLERATE(record) ((double*)((uint8_t*)record+16))
|
||||
#define pMS3FSDH_NUMSAMPLES(record) ((uint32_t*)((uint8_t*)record+24))
|
||||
#define pMS3FSDH_CRC(record) ((uint32_t*)((uint8_t*)record+28))
|
||||
#define pMS3FSDH_PUBVERSION(record) ((uint8_t*)((uint8_t*)record+32))
|
||||
#define pMS3FSDH_SIDLENGTH(record) ((uint8_t*)((uint8_t*)record+33))
|
||||
#define pMS3FSDH_EXTRALENGTH(record) ((uint16_t*)((uint8_t*)record+34))
|
||||
#define pMS3FSDH_DATALENGTH(record) ((uint32_t*)((uint8_t*)record+36))
|
||||
#define pMS3FSDH_SID(record) ((char*)((uint8_t*)record+40))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Fixed Section of Data Header
|
||||
* 48 bytes total
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* sequence_number char[6] 0
|
||||
* dataquality char 6
|
||||
* reserved char 7
|
||||
* station char[5] 8
|
||||
* location char[2] 13
|
||||
* channel char[3] 15
|
||||
* network char[2] 18
|
||||
* year uint16_t 20
|
||||
* day uint16_t 22
|
||||
* hour uint8_t 24
|
||||
* min uint8_t 25
|
||||
* sec uint8_t 26
|
||||
* unused uint8_t 27
|
||||
* fract uint16_t 28
|
||||
* numsamples uint16_t 30
|
||||
* samprate_fact int16_t 32
|
||||
* samprate_mult int16_t 34
|
||||
* act_flags uint8_t 36
|
||||
* io_flags uint8_t 37
|
||||
* dq_flags uint8_t 38
|
||||
* numblockettes uint8_t 39
|
||||
* time_correct int32_t 40
|
||||
* data_offset uint16_t 44
|
||||
* blockette_offset uint16_t 46
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2FSDH_SEQNUM(record) ((char*)record)
|
||||
#define pMS2FSDH_DATAQUALITY(record) ((char*)((uint8_t*)record+6))
|
||||
#define pMS2FSDH_RESERVED(record) ((char*)((uint8_t*)record+7))
|
||||
#define pMS2FSDH_STATION(record) ((char*)((uint8_t*)record+8))
|
||||
#define pMS2FSDH_LOCATION(record) ((char*)((uint8_t*)record+13))
|
||||
#define pMS2FSDH_CHANNEL(record) ((char*)((uint8_t*)record+15))
|
||||
#define pMS2FSDH_NETWORK(record) ((char*)((uint8_t*)record+18))
|
||||
#define pMS2FSDH_YEAR(record) ((uint16_t*)((uint8_t*)record+20))
|
||||
#define pMS2FSDH_DAY(record) ((uint16_t*)((uint8_t*)record+22))
|
||||
#define pMS2FSDH_HOUR(record) ((uint8_t*)((uint8_t*)record+24))
|
||||
#define pMS2FSDH_MIN(record) ((uint8_t*)((uint8_t*)record+25))
|
||||
#define pMS2FSDH_SEC(record) ((uint8_t*)((uint8_t*)record+26))
|
||||
#define pMS2FSDH_UNUSED(record) ((uint8_t*)((uint8_t*)record+27))
|
||||
#define pMS2FSDH_FSEC(record) ((uint16_t*)((uint8_t*)record+28))
|
||||
#define pMS2FSDH_NUMSAMPLES(record) ((uint16_t*)((uint8_t*)record+30))
|
||||
#define pMS2FSDH_SAMPLERATEFACT(record) ((int16_t*)((uint8_t*)record+32))
|
||||
#define pMS2FSDH_SAMPLERATEMULT(record) ((int16_t*)((uint8_t*)record+34))
|
||||
#define pMS2FSDH_ACTFLAGS(record) ((uint8_t*)((uint8_t*)record+36))
|
||||
#define pMS2FSDH_IOFLAGS(record) ((uint8_t*)((uint8_t*)record+37))
|
||||
#define pMS2FSDH_DQFLAGS(record) ((uint8_t*)((uint8_t*)record+38))
|
||||
#define pMS2FSDH_NUMBLOCKETTES(record) ((uint8_t*)((uint8_t*)record+39))
|
||||
#define pMS2FSDH_TIMECORRECT(record) ((int32_t*)((uint8_t*)record+40))
|
||||
#define pMS2FSDH_DATAOFFSET(record) ((uint16_t*)((uint8_t*)record+44))
|
||||
#define pMS2FSDH_BLOCKETTEOFFSET(record) ((uint16_t*)((uint8_t*)record+46))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 100 - sample rate
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* samprate float 4
|
||||
* flags uint8_t 8
|
||||
* reserved uint8_t[3] 9
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B100_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B100_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B100_SAMPRATE(blockette) ((float*)((uint8_t*)blockette+4))
|
||||
#define pMS2B100_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B100_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 200 - generic event detection
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* amplitude float 4
|
||||
* period float 8
|
||||
* background_est float 12
|
||||
* flags uint8_t 16
|
||||
* reserved uint8_t 17
|
||||
* year uint16_t 18
|
||||
* day uint16_t 20
|
||||
* hour uint8_t 22
|
||||
* min uint8_t 23
|
||||
* sec uint8_t 24
|
||||
* unused uint8_t 25
|
||||
* fract uint16_t 26
|
||||
* detector char[24] 28
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B200_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B200_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B200_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+4))
|
||||
#define pMS2B200_PERIOD(blockette) ((float*)((uint8_t*)blockette+8))
|
||||
#define pMS2B200_BACKGROUNDEST(blockette) ((float*)((uint8_t*)blockette+12))
|
||||
#define pMS2B200_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B200_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+17))
|
||||
#define pMS2B200_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+18))
|
||||
#define pMS2B200_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+20))
|
||||
#define pMS2B200_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+22))
|
||||
#define pMS2B200_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+23))
|
||||
#define pMS2B200_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+24))
|
||||
#define pMS2B200_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+25))
|
||||
#define pMS2B200_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+26))
|
||||
#define pMS2B200_DETECTOR(blockette) ((char*)((uint8_t*)blockette+28))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 201 - Murdock event detection
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* amplitude float 4
|
||||
* period float 8
|
||||
* background_est float 12
|
||||
* flags uint8_t 16
|
||||
* reserved uint8_t 17
|
||||
* year uint16_t 18
|
||||
* day uint16_t 20
|
||||
* hour uint8_t 22
|
||||
* min uint8_t 23
|
||||
* sec uint8_t 24
|
||||
* unused uint8_t 25
|
||||
* fract uint16_t 26
|
||||
* snr_values uint8_t[6] 28
|
||||
* loopback uint8_t 34
|
||||
* pick_algorithm uint8_t 35
|
||||
* detector char[24] 36
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B201_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B201_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B201_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+4))
|
||||
#define pMS2B201_PERIOD(blockette) ((float*)((uint8_t*)blockette+8))
|
||||
#define pMS2B201_BACKGROUNDEST(blockette) ((float*)((uint8_t*)blockette+12))
|
||||
#define pMS2B201_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B201_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+17))
|
||||
#define pMS2B201_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+18))
|
||||
#define pMS2B201_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+20))
|
||||
#define pMS2B201_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+22))
|
||||
#define pMS2B201_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+23))
|
||||
#define pMS2B201_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+24))
|
||||
#define pMS2B201_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+25))
|
||||
#define pMS2B201_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+26))
|
||||
#define pMS2B201_MEDSNR(blockette) ((uint8_t*)((uint8_t*)blockette+28))
|
||||
#define pMS2B201_LOOPBACK(blockette) ((uint8_t*)((uint8_t*)blockette+34))
|
||||
#define pMS2B201_PICKALGORITHM(blockette) ((uint8_t*)((uint8_t*)blockette+35))
|
||||
#define pMS2B201_DETECTOR(blockette) ((char*)((uint8_t*)blockette+36))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 300 - step calibration
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* year uint16_t 4
|
||||
* day uint16_t 6
|
||||
* hour uint8_t 8
|
||||
* min uint8_t 9
|
||||
* sec uint8_t 10
|
||||
* unused uint8_t 11
|
||||
* fract uint16_t 12
|
||||
* num calibrations uint8_t 14
|
||||
* flags uint8_t 15
|
||||
* step duration uint32_t 16
|
||||
* interval duration uint32_t 20
|
||||
* amplitude float 24
|
||||
* input channel char[3] 28
|
||||
* reserved uint8_t 31
|
||||
* reference amplitude uint32_t 32
|
||||
* coupling char[12] 36
|
||||
* rolloff char[12] 48
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B300_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B300_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B300_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B300_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B300_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B300_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
#define pMS2B300_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B300_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
|
||||
#define pMS2B300_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B300_NUMCALIBRATIONS(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B300_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
|
||||
#define pMS2B300_STEPDURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B300_INTERVALDURATION(blockette) ((uint32_t*)((uint8_t*)blockette+20))
|
||||
#define pMS2B300_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+24))
|
||||
#define pMS2B300_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+28))
|
||||
#define pMS2B300_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+31))
|
||||
#define pMS2B300_REFERENCEAMPLITUDE(blockette) ((uint32_t*)((uint8_t*)blockette+32))
|
||||
#define pMS2B300_COUPLING(blockette) ((char*)((uint8_t*)blockette+36))
|
||||
#define pMS2B300_ROLLOFF(blockette) ((char*)((uint8_t*)blockette+48))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 310 - sine calibration
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* year uint16_t 4
|
||||
* day uint16_t 6
|
||||
* hour uint8_t 8
|
||||
* min uint8_t 9
|
||||
* sec uint8_t 10
|
||||
* unused uint8_t 11
|
||||
* fract uint16_t 12
|
||||
* reserved1 uint8_t 14
|
||||
* flags uint8_t 15
|
||||
* duration uint32_t 16
|
||||
* period float 20
|
||||
* amplitude float 24
|
||||
* input channel char[3] 28
|
||||
* reserved2 uint8_t 31
|
||||
* reference amplitude uint32_t 32
|
||||
* coupling char[12] 36
|
||||
* rolloff char[12] 48
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B310_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B310_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B310_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B310_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B310_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B310_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
#define pMS2B310_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B310_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
|
||||
#define pMS2B310_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B310_RESERVED1(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B310_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
|
||||
#define pMS2B310_DURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B310_PERIOD(blockette) ((float*)((uint8_t*)blockette+20))
|
||||
#define pMS2B310_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+24))
|
||||
#define pMS2B310_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+28))
|
||||
#define pMS2B310_RESERVED2(blockette) ((uint8_t*)((uint8_t*)blockette+31))
|
||||
#define pMS2B310_REFERENCEAMPLITUDE(blockette) ((uint32_t*)((uint8_t*)blockette+32))
|
||||
#define pMS2B310_COUPLING(blockette) ((char*)((uint8_t*)blockette+36))
|
||||
#define pMS2B310_ROLLOFF(blockette) ((char*)((uint8_t*)blockette+48))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 320 - pseudo-random calibration
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* year uint16_t 4
|
||||
* day uint16_t 6
|
||||
* hour uint8_t 8
|
||||
* min uint8_t 9
|
||||
* sec uint8_t 10
|
||||
* unused uint8_t 11
|
||||
* fract uint16_t 12
|
||||
* reserved1 uint8_t 14
|
||||
* flags uint8_t 15
|
||||
* duration uint32_t 16
|
||||
* PtP amplitude float 20
|
||||
* input channel char[3] 24
|
||||
* reserved2 uint8_t 27
|
||||
* reference amplitude uint32_t 28
|
||||
* coupling char[12] 32
|
||||
* rolloff char[12] 44
|
||||
* noise type char[8] 56
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B320_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B320_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B320_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B320_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B320_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B320_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
#define pMS2B320_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B320_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
|
||||
#define pMS2B320_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B320_RESERVED1(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B320_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
|
||||
#define pMS2B320_DURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B320_PTPAMPLITUDE(blockette) ((float*)((uint8_t*)blockette+20))
|
||||
#define pMS2B320_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+24))
|
||||
#define pMS2B320_RESERVED2(blockette) ((uint8_t*)((uint8_t*)blockette+27))
|
||||
#define pMS2B320_REFERENCEAMPLITUDE(blockette) ((uint32_t*)((uint8_t*)blockette+28))
|
||||
#define pMS2B320_COUPLING(blockette) ((char*)((uint8_t*)blockette+32))
|
||||
#define pMS2B320_ROLLOFF(blockette) ((char*)((uint8_t*)blockette+44))
|
||||
#define pMS2B320_NOISETYPE(blockette) ((char*)((uint8_t*)blockette+56))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 390 - generic calibration
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* year uint16_t 4
|
||||
* day uint16_t 6
|
||||
* hour uint8_t 8
|
||||
* min uint8_t 9
|
||||
* sec uint8_t 10
|
||||
* unused uint8_t 11
|
||||
* fract uint16_t 12
|
||||
* reserved1 uint8_t 14
|
||||
* flags uint8_t 15
|
||||
* duration uint32_t 16
|
||||
* amplitude float 20
|
||||
* input channel char[3] 24
|
||||
* reserved2 uint8_t 27
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B390_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B390_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B390_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B390_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B390_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B390_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
#define pMS2B390_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B390_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
|
||||
#define pMS2B390_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B390_RESERVED1(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B390_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
|
||||
#define pMS2B390_DURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B390_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+20))
|
||||
#define pMS2B390_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+24))
|
||||
#define pMS2B390_RESERVED2(blockette) ((uint8_t*)((uint8_t*)blockette+27))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 395 - calibration abort
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* year uint16_t 4
|
||||
* day uint16_t 6
|
||||
* hour uint8_t 8
|
||||
* min uint8_t 9
|
||||
* sec uint8_t 10
|
||||
* unused uint8_t 11
|
||||
* fract uint16_t 12
|
||||
* reserved uint8_t[2] 14
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B395_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B395_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B395_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B395_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B395_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B395_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
#define pMS2B395_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B395_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
|
||||
#define pMS2B395_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B395_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 400 - beam
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* azimuth float 4
|
||||
* slowness float 8
|
||||
* configuration uint16_t 12
|
||||
* reserved uint8_t[2] 14
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B400_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B400_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B400_AZIMUTH(blockette) ((float*)((uint8_t*)blockette+4))
|
||||
#define pMS2B400_SLOWNESS(blockette) ((float*)((uint8_t*)blockette+8))
|
||||
#define pMS2B400_CONFIGURATION(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B400_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 405 - beam delay
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* delay values uint16_t[1] 4
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B405_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B405_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B405_DELAYVALUES(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 500 - timing
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* VCO correction float 4
|
||||
* year uint16_t 8
|
||||
* day uint16_t 10
|
||||
* hour uint8_t 12
|
||||
* min uint8_t 13
|
||||
* sec uint8_t 14
|
||||
* unused uint8_t 15
|
||||
* fract uint16_t 16
|
||||
* microsecond int8_t 18
|
||||
* reception quality uint8_t 19
|
||||
* exception count uint32_t 20
|
||||
* exception type char[16] 24
|
||||
* clock model char[32] 40
|
||||
* clock status char[128] 72
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B500_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B500_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B500_VCOCORRECTION(blockette) ((float*)((uint8_t*)blockette+4))
|
||||
#define pMS2B500_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B500_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B500_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B500_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+13))
|
||||
#define pMS2B500_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B500_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+15))
|
||||
#define pMS2B500_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B500_MICROSECOND(blockette) ((int8_t*)((uint8_t*)blockette+18))
|
||||
#define pMS2B500_RECEPTIONQUALITY(blockette) ((uint8_t*)((uint8_t*)blockette+19))
|
||||
#define pMS2B500_EXCEPTIONCOUNT(blockette) ((uint32_t*)((uint8_t*)blockette+20))
|
||||
#define pMS2B500_EXCEPTIONTYPE(blockette) ((char*)((uint8_t*)blockette+24))
|
||||
#define pMS2B500_CLOCKMODEL(blockette) ((char*)((uint8_t*)blockette+40))
|
||||
#define pMS2B500_CLOCKSTATUS(blockette) ((char*)((uint8_t*)blockette+72))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 1000 - data only SEED (miniSEED)
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* encoding uint8_t 4
|
||||
* byteorder uint8_t 5
|
||||
* reclen uint8_t 6
|
||||
* reserved uint8_t 7
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B1000_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B1000_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B1000_ENCODING(blockette) ((uint8_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B1000_BYTEORDER(blockette) ((uint8_t*)((uint8_t*)blockette+5))
|
||||
#define pMS2B1000_RECLEN(blockette) ((uint8_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B1000_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+7))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 1001 - data extension
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* timing quality uint8_t 4
|
||||
* microsecond int8_t 5
|
||||
* reserved uint8_t 6
|
||||
* frame count uint8_t 7
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B1001_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B1001_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B1001_TIMINGQUALITY(blockette) ((uint8_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B1001_MICROSECOND(blockette) ((int8_t*)((uint8_t*)blockette+5))
|
||||
#define pMS2B1001_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B1001_FRAMECOUNT(blockette) ((uint8_t*)((uint8_t*)blockette+7))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 2000 - opaque data
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* length uint16_t 4
|
||||
* data offset uint16_t 6
|
||||
* recnum uint32_t 8
|
||||
* byteorder uint8_t 12
|
||||
* flags uint8_t 13
|
||||
* numheaders uint8_t 14
|
||||
* payload char[1] 15
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B2000_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B2000_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B2000_LENGTH(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B2000_DATAOFFSET(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B2000_RECNUM(blockette) ((uint32_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B2000_BYTEORDER(blockette) ((uint8_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B2000_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+13))
|
||||
#define pMS2B2000_NUMHEADERS(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B2000_PAYLOAD(blockette) ((char*)((uint8_t*)blockette+15))
|
||||
|
||||
/***************************************************************************
|
||||
* Simple static inline convenience functions to swap bytes to "host
|
||||
* order", as determined by the swap flag.
|
||||
***************************************************************************/
|
||||
static inline int16_t
|
||||
HO2d (int16_t value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap2 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static inline uint16_t
|
||||
HO2u (uint16_t value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap2 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static inline int32_t
|
||||
HO4d (int32_t value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap4 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static inline uint32_t
|
||||
HO4u (uint32_t value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap4 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static inline float
|
||||
HO4f (float value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap4 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static inline double
|
||||
HO8f (double value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap8 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Macro to test for sane year and day values, used primarily to
|
||||
* determine if byte order swapping is needed for miniSEED 2.x.
|
||||
*
|
||||
* Year : between 1900 and 2100
|
||||
* Day : between 1 and 366
|
||||
*
|
||||
* This test is non-unique (non-deterministic) for days 1, 256 and 257
|
||||
* in the year 2056 because the swapped values are also within range.
|
||||
* If you are using this in 2056 to determine the byte order of miniSEED 2
|
||||
* you have my deepest sympathies.
|
||||
*/
|
||||
#define MS_ISVALIDYEARDAY(Y,D) (Y >= 1900 && Y <= 2100 && D >= 1 && D <= 366)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,830 @@
|
||||
/***************************************************************************
|
||||
* I/O handling routines, for files and URLs.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
/* Define _LARGEFILE_SOURCE to get ftello/fseeko on some systems (Linux) */
|
||||
#define _LARGEFILE_SOURCE 1
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "msio.h"
|
||||
|
||||
/* Include libcurl library header if URL supported is requested */
|
||||
#if defined(LIBMSEED_URL)
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
/* Control for enabling debugging information */
|
||||
int libmseed_url_debug = -1;
|
||||
|
||||
/* Control for SSL peer and host verification */
|
||||
long libmseed_ssl_noverify = -1;
|
||||
|
||||
/* A global libcurl easy handle for configuration options */
|
||||
CURL *gCURLeasy = NULL;
|
||||
|
||||
/* A global libcurl list of headers */
|
||||
struct curl_slist *gCURLheaders = NULL;
|
||||
|
||||
/* Receving callback parameters */
|
||||
struct recv_callback_parameters
|
||||
{
|
||||
char *buffer;
|
||||
size_t size;
|
||||
int is_paused;
|
||||
};
|
||||
|
||||
/* Header callback parameters */
|
||||
struct header_callback_parameters
|
||||
{
|
||||
int64_t *startoffset;
|
||||
int64_t *endoffset;
|
||||
};
|
||||
|
||||
/*********************************************************************
|
||||
* Callback fired when recv'ing data using libcurl.
|
||||
*
|
||||
* The destination buffer pointer and size in the callback parameters
|
||||
* are adjusted as data are added.
|
||||
*
|
||||
* Returns number of bytes added to the destination buffer.
|
||||
*********************************************************************/
|
||||
static size_t
|
||||
recv_callback (char *buffer, size_t size, size_t num, void *userdata)
|
||||
{
|
||||
struct recv_callback_parameters *rcp = (struct recv_callback_parameters *)userdata;
|
||||
|
||||
if (!buffer || !userdata)
|
||||
return 0;
|
||||
|
||||
size *= num;
|
||||
|
||||
/* Pause connection if passed data does not fit into destination buffer */
|
||||
if (size > rcp->size)
|
||||
{
|
||||
rcp->is_paused = 1;
|
||||
return CURL_WRITEFUNC_PAUSE;
|
||||
}
|
||||
/* Otherwise, copy data to destination buffer */
|
||||
else
|
||||
{
|
||||
memcpy (rcp->buffer, buffer, size);
|
||||
rcp->buffer += size;
|
||||
rcp->size -= size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Callback fired when receiving headers using libcurl.
|
||||
*
|
||||
* Returns number of bytes processed for success.
|
||||
*********************************************************************/
|
||||
static size_t
|
||||
header_callback (char *buffer, size_t size, size_t num, void *userdata)
|
||||
{
|
||||
struct header_callback_parameters *hcp = (struct header_callback_parameters *)userdata;
|
||||
|
||||
char startstr[21] = {0}; /* Maximum of 20 digit value */
|
||||
char endstr[21] = {0}; /* Maximum of 20 digit value */
|
||||
int startdigits = 0;
|
||||
int enddigits = 0;
|
||||
char *dash = NULL;
|
||||
char *ptr;
|
||||
|
||||
if (!buffer || !userdata)
|
||||
return 0;
|
||||
|
||||
size *= num;
|
||||
|
||||
/* Parse and store: "Content-Range: bytes START-END/TOTAL"
|
||||
* e.g. Content-Range: bytes 512-1023/4096 */
|
||||
if (size > 22 && strncasecmp (buffer, "Content-Range: bytes", 20) == 0)
|
||||
{
|
||||
/* Process each character, starting just afer "bytes" unit */
|
||||
for (ptr = buffer + 20; *ptr != '\0' && (ptr - buffer) < size; ptr++)
|
||||
{
|
||||
/* Skip spaces before start of range */
|
||||
if (*ptr == ' ' && startdigits == 0)
|
||||
continue;
|
||||
/* Digits before dash, part of start */
|
||||
else if (isdigit (*ptr) && dash == NULL)
|
||||
startstr[startdigits++] = *ptr;
|
||||
/* Digits after dash, part of end */
|
||||
else if (isdigit (*ptr) && dash != NULL)
|
||||
endstr[enddigits++] = *ptr;
|
||||
/* If first dash found, store pointer */
|
||||
else if (*ptr == '-' && dash == NULL)
|
||||
dash = ptr;
|
||||
/* Nothing else is part of the range */
|
||||
else
|
||||
break;
|
||||
|
||||
/* If digit sequences have exceeded limits, not a valid range */
|
||||
if (startdigits >= sizeof (startstr) || enddigits >= sizeof (endstr))
|
||||
{
|
||||
startdigits = 0;
|
||||
enddigits = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert start and end values to numbers if non-zero length */
|
||||
if (hcp->startoffset && startdigits)
|
||||
*hcp->startoffset = (int64_t) strtoull (startstr, NULL, 10);
|
||||
|
||||
if (hcp->endoffset && enddigits)
|
||||
*hcp->endoffset = (int64_t) strtoull (endstr, NULL, 10);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif /* defined(LIBMSEED_URL) */
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* msio_fopen:
|
||||
*
|
||||
* Determine if requested path is a regular file or a URL and open or
|
||||
* initialize as appropriate.
|
||||
*
|
||||
* The 'mode' argument is only for file-system paths and ignored for
|
||||
* URLs. If 'mode' is set to NULL, default is 'rb' mode.
|
||||
*
|
||||
* If 'startoffset' or 'endoffset' are non-zero they will be used to
|
||||
* position the stream for reading, either setting the read position
|
||||
* of a file or requesting a range via HTTP. These will be set to the
|
||||
* actual range if reported via HTTP, which may be different than
|
||||
* requested.
|
||||
*
|
||||
* Return 0 on success and -1 on error.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
***************************************************************************/
|
||||
int
|
||||
msio_fopen (LMIO *io, const char *path, const char *mode,
|
||||
int64_t *startoffset, int64_t *endoffset)
|
||||
{
|
||||
int knownfile = 0;
|
||||
|
||||
if (!io || !path)
|
||||
return -1;
|
||||
|
||||
if (!mode)
|
||||
mode = "rb";
|
||||
|
||||
/* Treat "file://" specifications as local files by removing the scheme */
|
||||
if (!strncasecmp (path, "file://", 7))
|
||||
{
|
||||
path += 7;
|
||||
knownfile = 1;
|
||||
}
|
||||
|
||||
/* Test for URL scheme via "://" */
|
||||
if (!knownfile && strstr (path, "://"))
|
||||
{
|
||||
#if !defined(LIBMSEED_URL)
|
||||
ms_log (2, "URL support not included in library for %s\n", path);
|
||||
return -1;
|
||||
#else
|
||||
long response_code;
|
||||
struct header_callback_parameters hcp;
|
||||
|
||||
io->type = LMIO_URL;
|
||||
|
||||
/* Check for URL debugging environment variable */
|
||||
if (libmseed_url_debug < 0)
|
||||
{
|
||||
if (getenv ("LIBMSEED_URL_DEBUG"))
|
||||
libmseed_url_debug = 1;
|
||||
else
|
||||
libmseed_url_debug = 0;
|
||||
}
|
||||
|
||||
/* Check for SSL peer/host verify environment variable */
|
||||
if (libmseed_ssl_noverify < 0)
|
||||
{
|
||||
if (getenv ("LIBMSEED_SSL_NOVERIFY"))
|
||||
libmseed_ssl_noverify = 1;
|
||||
else
|
||||
libmseed_ssl_noverify = 0;
|
||||
}
|
||||
|
||||
/* Configure the libcurl easy handle, duplicate global options if present */
|
||||
io->handle = (gCURLeasy) ? curl_easy_duphandle (gCURLeasy) : curl_easy_init ();
|
||||
|
||||
if (io->handle == NULL)
|
||||
{
|
||||
ms_log (2, "Cannot initialize CURL handle\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* URL debug */
|
||||
if (libmseed_url_debug && curl_easy_setopt (io->handle, CURLOPT_VERBOSE, 1L) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_VERBOSE\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* SSL peer and host verification */
|
||||
if (libmseed_ssl_noverify &&
|
||||
(curl_easy_setopt (io->handle, CURLOPT_SSL_VERIFYPEER, 0L) != CURLE_OK ||
|
||||
curl_easy_setopt (io->handle, CURLOPT_SSL_VERIFYHOST, 0L) != CURLE_OK))
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_SSL_VERIFYPEER and/or CURLOPT_SSL_VERIFYHOST\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set URL */
|
||||
if (curl_easy_setopt (io->handle, CURLOPT_URL, path) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_URL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set default User-Agent header, can be overridden via custom header */
|
||||
if (curl_easy_setopt (io->handle, CURLOPT_USERAGENT,
|
||||
"libmseed/" LIBMSEED_VERSION " libcurl/" LIBCURL_VERSION) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set default CURLOPT_USERAGENT\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Disable signals */
|
||||
if (curl_easy_setopt (io->handle, CURLOPT_NOSIGNAL, 1L) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_NOSIGNAL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return failure codes on errors */
|
||||
if (curl_easy_setopt (io->handle, CURLOPT_FAILONERROR, 1L) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_FAILONERROR\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Follow HTTP redirects */
|
||||
if (curl_easy_setopt (io->handle, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_FOLLOWLOCATION\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Configure write callback for recv'ed data */
|
||||
if (curl_easy_setopt (io->handle, CURLOPT_WRITEFUNCTION, recv_callback) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_WRITEFUNCTION\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Configure the libcurl multi handle, for use with the asynchronous interface */
|
||||
if ((io->handle2 = curl_multi_init ()) == NULL)
|
||||
{
|
||||
ms_log (2, "Cannot initialize CURL multi handle\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (curl_multi_add_handle (io->handle2, io->handle) != CURLM_OK)
|
||||
{
|
||||
ms_log (2, "Cannot add CURL handle to multi handle\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set byte ranging */
|
||||
if ((startoffset && *startoffset > 0) || (endoffset && *endoffset > 0))
|
||||
{
|
||||
char startstr[21] = {0};
|
||||
char endstr[21] = {0};
|
||||
char rangestr[42];
|
||||
|
||||
/* Build Range header value.
|
||||
* If start is undefined set it to zero if end is defined. */
|
||||
if (*startoffset > 0)
|
||||
snprintf (startstr, sizeof (startstr), "%" PRId64, *startoffset);
|
||||
else if (*endoffset > 0)
|
||||
snprintf (startstr, sizeof (startstr), "0");
|
||||
if (*endoffset > 0)
|
||||
snprintf (endstr, sizeof (endstr), "%" PRId64, *endoffset);
|
||||
|
||||
snprintf (rangestr, sizeof (rangestr), "%s-%s", startstr, endstr);
|
||||
|
||||
/* Set Range header */
|
||||
if (curl_easy_setopt (io->handle, CURLOPT_RANGE, rangestr) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_RANGE to '%s'\n", rangestr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up header callback */
|
||||
if (startoffset || endoffset)
|
||||
{
|
||||
hcp.startoffset = startoffset;
|
||||
hcp.endoffset = endoffset;
|
||||
|
||||
/* Configure header callback */
|
||||
if (curl_easy_setopt (io->handle, CURLOPT_HEADERFUNCTION, header_callback) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_HEADERFUNCTION\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (curl_easy_setopt (io->handle, CURLOPT_HEADERDATA, (void *)&hcp) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_HEADERDATA\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set custom headers */
|
||||
if (gCURLheaders && curl_easy_setopt (io->handle, CURLOPT_HTTPHEADER, gCURLheaders) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_HTTPHEADER\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set connection as still running */
|
||||
io->still_running = 1;
|
||||
|
||||
/* Start connection, get status & headers, without consuming any data */
|
||||
msio_fread (io, NULL, 0);
|
||||
|
||||
curl_easy_getinfo (io->handle, CURLINFO_RESPONSE_CODE, &response_code);
|
||||
|
||||
if (response_code == 404)
|
||||
{
|
||||
ms_log (2, "Cannot open %s: Not Found (404)\n", path);
|
||||
return -1;
|
||||
}
|
||||
else if (response_code >= 400 && response_code < 600)
|
||||
{
|
||||
ms_log (2, "Cannot open %s: response code %ld\n", path, response_code);
|
||||
return -1;
|
||||
}
|
||||
#endif /* defined(LIBMSEED_URL) */
|
||||
}
|
||||
else
|
||||
{
|
||||
io->type = LMIO_FILE;
|
||||
|
||||
if ((io->handle = fopen (path, mode)) == NULL)
|
||||
{
|
||||
ms_log (2, "Cannot open: %s (%s)\n", path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Seek to position if start offset is provided */
|
||||
if (startoffset && *startoffset > 0)
|
||||
{
|
||||
if (lmp_fseek64 (io->handle, *startoffset, SEEK_SET))
|
||||
{
|
||||
ms_log (2, "Cannot seek in %s to offset %" PRId64 "\n", path, *startoffset);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* End of msio_fopen() */
|
||||
|
||||
/*********************************************************************
|
||||
* msio_fclose:
|
||||
*
|
||||
* Close an IO handle.
|
||||
*
|
||||
* Returns 0 on success and negative value on error.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
*********************************************************************/
|
||||
int
|
||||
msio_fclose (LMIO *io)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (!io)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'io'\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (io->handle == NULL || io->type == LMIO_NULL)
|
||||
return 0;
|
||||
|
||||
if (io->type == LMIO_FILE)
|
||||
{
|
||||
rv = fclose (io->handle);
|
||||
|
||||
if (rv)
|
||||
{
|
||||
ms_log (2, "Error closing file (%s)\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (io->type == LMIO_URL)
|
||||
{
|
||||
#if !defined(LIBMSEED_URL)
|
||||
ms_log (2, "URL support not included in library\n");
|
||||
return -1;
|
||||
#else
|
||||
curl_multi_remove_handle (io->handle2, io->handle);
|
||||
curl_easy_cleanup (io->handle);
|
||||
curl_multi_cleanup (io->handle2);
|
||||
#endif
|
||||
}
|
||||
|
||||
io->type = LMIO_NULL;
|
||||
io->handle = NULL;
|
||||
io->handle2 = NULL;
|
||||
|
||||
return 0;
|
||||
} /* End of msio_fclose() */
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* msio_fread:
|
||||
*
|
||||
* Read data from the identified IO handle into the specified buffer.
|
||||
* Up to the requested 'size' bytes are read.
|
||||
*
|
||||
* For URL support, with defined(LIBMSEED_URL), the destination
|
||||
* receive buffer MUST be at least as big as the curl receive buffer
|
||||
* (CURLOPT_BUFFERSIZE, which defaults to CURL_MAX_WRITE_SIZE of 16kB)
|
||||
* or the maximum size of a retrieved object if less than
|
||||
* CURL_MAX_WRITE_SIZE. The caller must ensure this.
|
||||
*
|
||||
* Returns the number of bytes read on success and a negative value on
|
||||
* error.
|
||||
*********************************************************************/
|
||||
size_t
|
||||
msio_fread (LMIO *io, void *buffer, size_t size)
|
||||
{
|
||||
size_t read = 0;
|
||||
|
||||
if (!io)
|
||||
return -1;
|
||||
|
||||
if (!buffer && size > 0)
|
||||
{
|
||||
ms_log (2, "No buffer specified for size is > 0\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read from regular file stream */
|
||||
if (io->type == LMIO_FILE)
|
||||
{
|
||||
read = fread (buffer, 1, size, io->handle);
|
||||
}
|
||||
/* Read from URL stream */
|
||||
else if (io->type == LMIO_URL)
|
||||
{
|
||||
#if !defined(LIBMSEED_URL)
|
||||
ms_log (2, "URL support not included in library\n");
|
||||
return -1;
|
||||
#else
|
||||
struct recv_callback_parameters rcp;
|
||||
struct timeval timeout;
|
||||
fd_set fdread;
|
||||
fd_set fdwrite;
|
||||
fd_set fdexcep;
|
||||
long curl_timeo = -1;
|
||||
int maxfd = -1;
|
||||
int rc;
|
||||
|
||||
if (!io->still_running)
|
||||
return 0;
|
||||
|
||||
/* Set up destination buffer in write callback parameters */
|
||||
rcp.buffer = buffer;
|
||||
rcp.size = size;
|
||||
if (curl_easy_setopt (io->handle, CURLOPT_WRITEDATA, (void *)&rcp) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_WRITEDATA\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Unpause connection */
|
||||
curl_easy_pause (io->handle, CURLPAUSE_CONT);
|
||||
rcp.is_paused = 0;
|
||||
|
||||
/* Receive data while connection running, destination space available
|
||||
* and connection is not paused. */
|
||||
do
|
||||
{
|
||||
/* Default timeout for read failure */
|
||||
timeout.tv_sec = 60;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
curl_multi_timeout (io->handle2, &curl_timeo);
|
||||
|
||||
/* Tailor timeout based on maximum suggested by libcurl */
|
||||
if (curl_timeo >= 0)
|
||||
{
|
||||
timeout.tv_sec = curl_timeo / 1000;
|
||||
if (timeout.tv_sec > 1)
|
||||
timeout.tv_sec = 1;
|
||||
else
|
||||
timeout.tv_usec = (curl_timeo % 1000) * 1000;
|
||||
}
|
||||
|
||||
FD_ZERO (&fdread);
|
||||
FD_ZERO (&fdwrite);
|
||||
FD_ZERO (&fdexcep);
|
||||
|
||||
/* Extract descriptors from the multi-handle */
|
||||
if (curl_multi_fdset (io->handle2, &fdread, &fdwrite, &fdexcep, &maxfd) != CURLM_OK)
|
||||
{
|
||||
ms_log (2, "Error with curl_multi_fdset()\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* libcurl/system needs time to work, sleep 100 milliseconds */
|
||||
if (maxfd == -1)
|
||||
{
|
||||
lmp_nanosleep (100000000);
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = select (maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
|
||||
}
|
||||
|
||||
/* Receive data */
|
||||
if (rc >= 0)
|
||||
{
|
||||
curl_multi_perform (io->handle2, &io->still_running);
|
||||
}
|
||||
} while (io->still_running > 0 && !rcp.is_paused && (rcp.size > 0 || rcp.buffer == NULL));
|
||||
|
||||
read = size - rcp.size;
|
||||
|
||||
#endif /* defined(LIBMSEED_URL) */
|
||||
}
|
||||
|
||||
return read;
|
||||
} /* End of msio_fread() */
|
||||
|
||||
/*********************************************************************
|
||||
* msio_feof:
|
||||
*
|
||||
* Test if end-of-stream.
|
||||
*
|
||||
* Returns 1 when stream is at end, 0 if not, and -1 on error.
|
||||
*********************************************************************/
|
||||
int
|
||||
msio_feof (LMIO *io)
|
||||
{
|
||||
if (!io)
|
||||
return 0;
|
||||
|
||||
if (io->handle == NULL || io->type == LMIO_NULL)
|
||||
return 0;
|
||||
|
||||
if (io->type == LMIO_FILE)
|
||||
{
|
||||
if (feof ((FILE *)io->handle))
|
||||
return 1;
|
||||
}
|
||||
else if (io->type == LMIO_URL)
|
||||
{
|
||||
#if !defined(LIBMSEED_URL)
|
||||
ms_log (2, "URL support not included in library\n");
|
||||
return -1;
|
||||
#else
|
||||
/* The still_running flag is only changed by curl_multi_perform()
|
||||
* and indicates current "transfers in progress". Presumably no data
|
||||
* are in internal libcurl buffers either. */
|
||||
if (!io->still_running)
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* End of msio_feof() */
|
||||
|
||||
/*********************************************************************
|
||||
* msio_url_useragent:
|
||||
*
|
||||
* Set global User-Agent header for URL-based IO.
|
||||
*
|
||||
* The header is built as "PROGRAM/VERSION libmseed/version libcurl/version"
|
||||
* where VERSION is optional.
|
||||
*
|
||||
* Returns 0 on succes non-zero otherwise.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
*********************************************************************/
|
||||
int
|
||||
msio_url_useragent (const char *program, const char *version)
|
||||
{
|
||||
if (!program)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'program'\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(LIBMSEED_URL)
|
||||
ms_log (2, "URL support not included in library\n");
|
||||
return -1;
|
||||
#else
|
||||
char header[1024];
|
||||
|
||||
/* Build User-Agent header and add internal versions */
|
||||
snprintf (header, sizeof (header),
|
||||
"User-Agent: %s%s%s libmseed/" LIBMSEED_VERSION " libcurl/" LIBCURL_VERSION,
|
||||
program,
|
||||
(version) ? "/" : "",
|
||||
(version) ? version : "");
|
||||
|
||||
return msio_url_addheader (header);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
} /* End of msio_url_useragent() */
|
||||
|
||||
/*********************************************************************
|
||||
* msio_url_userpassword:
|
||||
*
|
||||
* Set global user-password credentials for URL-based IO.
|
||||
*
|
||||
* Returns 0 on succes non-zero otherwise.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
*********************************************************************/
|
||||
int
|
||||
msio_url_userpassword (const char *userpassword)
|
||||
{
|
||||
if (!userpassword)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'userpassword'\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(LIBMSEED_URL)
|
||||
ms_log (2, "URL support not included in library\n");
|
||||
return -1;
|
||||
#else
|
||||
if (gCURLeasy == NULL && (gCURLeasy = curl_easy_init ()) == NULL)
|
||||
return -1;
|
||||
|
||||
/* Allow any authentication, libcurl will pick the most secure */
|
||||
if (curl_easy_setopt (gCURLeasy, CURLOPT_HTTPAUTH, CURLAUTH_ANY) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_HTTPAUTH\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (curl_easy_setopt (gCURLeasy, CURLOPT_USERPWD, userpassword) != CURLE_OK)
|
||||
{
|
||||
ms_log (2, "Cannot set CURLOPT_USERPWD\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
} /* End of msio_url_userpassword() */
|
||||
|
||||
/*********************************************************************
|
||||
* msio_url_addheader:
|
||||
*
|
||||
* Add header to global list for URL-based IO.
|
||||
*
|
||||
* Returns 0 on succes non-zero otherwise.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
*********************************************************************/
|
||||
int
|
||||
msio_url_addheader (const char *header)
|
||||
{
|
||||
if (!header)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'header'\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(LIBMSEED_URL)
|
||||
ms_log (2, "URL support not included in library\n");
|
||||
return -1;
|
||||
#else
|
||||
struct curl_slist *slist = NULL;
|
||||
|
||||
slist = curl_slist_append (gCURLheaders, header);
|
||||
|
||||
if (slist == NULL)
|
||||
{
|
||||
ms_log (2, "Error adding header to list: %s\n", header);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gCURLheaders = slist;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
} /* End of msio_url_addheader() */
|
||||
|
||||
/*********************************************************************
|
||||
* msio_url_freeheaders:
|
||||
*
|
||||
* Free the global list of headers for URL-based IO.
|
||||
*********************************************************************/
|
||||
void
|
||||
msio_url_freeheaders (void)
|
||||
{
|
||||
#if !defined(LIBMSEED_URL)
|
||||
ms_log (2, "URL support not included in library\n");
|
||||
return;
|
||||
#else
|
||||
if (gCURLheaders != NULL)
|
||||
{
|
||||
curl_slist_free_all (gCURLheaders);
|
||||
gCURLheaders = NULL;
|
||||
}
|
||||
#endif
|
||||
} /* End of msio_url_freeheaders() */
|
||||
|
||||
/***************************************************************************
|
||||
* lmp_ftell64:
|
||||
*
|
||||
* Return the current file position for the specified descriptor using
|
||||
* the system's closest match to the POSIX ftello().
|
||||
***************************************************************************/
|
||||
int64_t
|
||||
lmp_ftell64 (FILE *stream)
|
||||
{
|
||||
#if defined(LMP_WIN)
|
||||
return (int64_t)_ftelli64 (stream);
|
||||
#else
|
||||
return (int64_t)ftello (stream);
|
||||
#endif
|
||||
} /* End of lmp_ftell64() */
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* lmp_fseek64:
|
||||
*
|
||||
* Seek to a specific file position for the specified descriptor using
|
||||
* the system's closest match to the POSIX fseeko().
|
||||
***************************************************************************/
|
||||
int
|
||||
lmp_fseek64 (FILE *stream, int64_t offset, int whence)
|
||||
{
|
||||
#if defined(LMP_WIN)
|
||||
return (int)_fseeki64 (stream, offset, whence);
|
||||
#else
|
||||
return (int)fseeko (stream, offset, whence);
|
||||
#endif
|
||||
} /* End of lmp_fseeko() */
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* @brief Sleep for a specified number of nanoseconds
|
||||
*
|
||||
* Sleep for a given number of nanoseconds. Under WIN use SleepEx()
|
||||
* and is limited to millisecond resolution. For all others use the
|
||||
* POSIX.4 nanosleep(), which can be interrupted by signals.
|
||||
*
|
||||
* @param nanoseconds Nanoseconds to sleep
|
||||
*
|
||||
* @return On non-WIN: the remaining nanoseconds are returned if the
|
||||
* requested interval is interrupted.
|
||||
***************************************************************************/
|
||||
uint64_t
|
||||
lmp_nanosleep (uint64_t nanoseconds)
|
||||
{
|
||||
#if defined(LMP_WIN)
|
||||
|
||||
/* SleepEx is limited to milliseconds */
|
||||
SleepEx ((DWORD) (nanoseconds / 1e6), 1);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
|
||||
struct timespec treq, trem;
|
||||
|
||||
treq.tv_sec = (time_t) (nanoseconds / 1e9);
|
||||
treq.tv_nsec = (long)(nanoseconds - (uint64_t)treq.tv_sec * 1e9);
|
||||
|
||||
nanosleep (&treq, &trem);
|
||||
|
||||
return trem.tv_sec * 1e9 + trem.tv_nsec;
|
||||
|
||||
#endif
|
||||
} /* End of lmp_nanosleep() */
|
@ -0,0 +1,44 @@
|
||||
/***************************************************************************
|
||||
* Interface declarations for routines in fio.c
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MSIO_H
|
||||
#define MSIO_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "libmseed.h"
|
||||
|
||||
extern int msio_fopen (LMIO *io, const char *path, const char *mode,
|
||||
int64_t *startoffset, int64_t *endoffset);
|
||||
extern int msio_fclose (LMIO *io);
|
||||
extern size_t msio_fread (LMIO *io, void *buffer, size_t size);
|
||||
extern int msio_feof (LMIO *io);
|
||||
extern int msio_url_useragent (const char *program, const char *version);
|
||||
extern int msio_url_userpassword (const char *userpassword);
|
||||
extern int msio_url_addheader (const char *header);
|
||||
extern void msio_url_freeheaders (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,395 @@
|
||||
/***************************************************************************
|
||||
* Generic routines to operate on miniSEED records.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "libmseed.h"
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Initialize and return an ::MS3Record
|
||||
*
|
||||
* Memory is allocated if for a new ::MS3Record if \a msr is NULL.
|
||||
*
|
||||
* If memory for the \c datasamples field has been allocated the pointer
|
||||
* will be retained for reuse. If memory for extra headers has been
|
||||
* allocated it will be released.
|
||||
*
|
||||
* @param[in] msr A ::MS3Record to re-initialize
|
||||
*
|
||||
* @returns a pointer to a ::MS3Record struct on success or NULL on error.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
***************************************************************************/
|
||||
MS3Record *
|
||||
msr3_init (MS3Record *msr)
|
||||
{
|
||||
void *datasamples = NULL;
|
||||
size_t datasize = 0;
|
||||
|
||||
if (!msr)
|
||||
{
|
||||
msr = (MS3Record *)libmseed_memory.malloc (sizeof (MS3Record));
|
||||
}
|
||||
else
|
||||
{
|
||||
datasamples = msr->datasamples;
|
||||
datasize = msr->datasize;
|
||||
|
||||
if (msr->extra)
|
||||
libmseed_memory.free (msr->extra);
|
||||
}
|
||||
|
||||
if (msr == NULL)
|
||||
{
|
||||
ms_log (2, "Cannot allocate memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset (msr, 0, sizeof (MS3Record));
|
||||
|
||||
msr->datasamples = datasamples;
|
||||
msr->datasize = datasize;
|
||||
|
||||
msr->reclen = -1;
|
||||
msr->samplecnt = -1;
|
||||
msr->encoding = -1;
|
||||
|
||||
return msr;
|
||||
} /* End of msr3_init() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Free all memory associated with a ::MS3Record
|
||||
*
|
||||
* Free all memory associated with a ::MS3Record, including extra
|
||||
* header and data samples if present.
|
||||
*
|
||||
* @param[in] ppmsr Pointer to point of the ::MS3Record to free
|
||||
***************************************************************************/
|
||||
void
|
||||
msr3_free (MS3Record **ppmsr)
|
||||
{
|
||||
if (ppmsr != NULL && *ppmsr != 0)
|
||||
{
|
||||
if ((*ppmsr)->extra)
|
||||
libmseed_memory.free ((*ppmsr)->extra);
|
||||
|
||||
if ((*ppmsr)->datasamples)
|
||||
libmseed_memory.free ((*ppmsr)->datasamples);
|
||||
|
||||
libmseed_memory.free (*ppmsr);
|
||||
|
||||
*ppmsr = NULL;
|
||||
}
|
||||
} /* End of msr3_free() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Duplicate a ::MS3Record
|
||||
*
|
||||
* Extra headers are duplicated as well.
|
||||
*
|
||||
* If the \a datadup flag is true (non-zero) and the source
|
||||
* ::MS3Record has associated data samples copy them as well.
|
||||
*
|
||||
* @param[in] msr ::MS3Record to duplicate
|
||||
* @param[in] datadup Flag to control duplication of data samples
|
||||
*
|
||||
* @returns Pointer to a new ::MS3Record on success and NULL on error
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
***************************************************************************/
|
||||
MS3Record *
|
||||
msr3_duplicate (const MS3Record *msr, int8_t datadup)
|
||||
{
|
||||
MS3Record *dupmsr = 0;
|
||||
|
||||
if (!msr)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'msr'\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate target MS3Record structure */
|
||||
if ((dupmsr = msr3_init (NULL)) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Copy MS3Record structure */
|
||||
memcpy (dupmsr, msr, sizeof (MS3Record));
|
||||
|
||||
/* Disconnect pointers from the source structure and reference values */
|
||||
dupmsr->extra = NULL;
|
||||
dupmsr->extralength = 0;
|
||||
dupmsr->datasamples = NULL;
|
||||
dupmsr->datasize = 0;
|
||||
dupmsr->numsamples = 0;
|
||||
|
||||
/* Copy extra headers */
|
||||
if (msr->extralength > 0 && msr->extra)
|
||||
{
|
||||
/* Allocate memory for new FSDH structure */
|
||||
if ((dupmsr->extra = (char *)libmseed_memory.malloc (msr->extralength)) == NULL)
|
||||
{
|
||||
ms_log (2, "Error allocating memory\n");
|
||||
msr3_free (&dupmsr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy (dupmsr->extra, msr->extra, msr->extralength);
|
||||
|
||||
if (dupmsr->extra)
|
||||
dupmsr->extralength = msr->extralength;
|
||||
}
|
||||
|
||||
/* Copy data samples if requested and available */
|
||||
if (datadup && msr->numsamples > 0 && msr->datasize > 0 && msr->datasamples)
|
||||
{
|
||||
/* Allocate memory for new data array */
|
||||
if ((dupmsr->datasamples = libmseed_memory.malloc ((size_t) (msr->datasize))) == NULL)
|
||||
{
|
||||
ms_log (2, "Error allocating memory\n");
|
||||
msr3_free (&dupmsr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy (dupmsr->datasamples, msr->datasamples, msr->datasize);
|
||||
|
||||
if (dupmsr->datasamples)
|
||||
{
|
||||
dupmsr->datasize = msr->datasize;
|
||||
dupmsr->numsamples = msr->numsamples;
|
||||
}
|
||||
}
|
||||
|
||||
return dupmsr;
|
||||
} /* End of msr3_duplicate() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Calculate time of the last sample in a record
|
||||
*
|
||||
* If leap seconds have been loaded into the internal library list:
|
||||
* when a record completely contains a leap second, starts before and
|
||||
* ends after, the calculated end time will be adjusted (reduced) by
|
||||
* one second.
|
||||
* @note On the epoch time scale the value of a leap second is the
|
||||
* same as the second following the leap second, without external
|
||||
* information the values are ambiguous.
|
||||
* \sa ms_readleapsecondfile()
|
||||
*
|
||||
* @param[in] msr ::MS3Record to calculate end time of
|
||||
*
|
||||
* @returns Time of the last sample on success and NSTERROR on error.
|
||||
***************************************************************************/
|
||||
nstime_t
|
||||
msr3_endtime (const MS3Record *msr)
|
||||
{
|
||||
int64_t sampleoffset = 0;
|
||||
|
||||
if (!msr)
|
||||
return NSTERROR;
|
||||
|
||||
if (msr->samplecnt > 0)
|
||||
sampleoffset = msr->samplecnt - 1;
|
||||
|
||||
return ms_sampletime (msr->starttime, sampleoffset, msr->samprate);
|
||||
} /* End of msr3_endtime() */
|
||||
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Print header values of an MS3Record
|
||||
*
|
||||
* @param[in] msr ::MS3Record to print
|
||||
* @param[in] details Flags to control the level of details:
|
||||
* @parblock
|
||||
* - \c 0 - print a single summary line
|
||||
* - \c 1 - print most details of header
|
||||
* - \c >1 - print all details of header and extra headers if present
|
||||
* @endparblock
|
||||
***************************************************************************/
|
||||
void
|
||||
msr3_print (const MS3Record *msr, int8_t details)
|
||||
{
|
||||
char time[40];
|
||||
char b;
|
||||
|
||||
if (!msr)
|
||||
return;
|
||||
|
||||
/* Generate a start time string */
|
||||
ms_nstime2timestr (msr->starttime, time, ISOMONTHDAY_DOY_Z, NANO_MICRO);
|
||||
|
||||
/* Report information in the fixed header */
|
||||
if (details > 0)
|
||||
{
|
||||
ms_log (0, "%s, version %d, %d bytes (format: %d)\n",
|
||||
msr->sid, msr->pubversion, msr->reclen, msr->formatversion);
|
||||
ms_log (0, " start time: %s\n", time);
|
||||
ms_log (0, " number of samples: %" PRId64 "\n", msr->samplecnt);
|
||||
ms_log (0, " sample rate (Hz): %.10g\n", msr3_sampratehz(msr));
|
||||
|
||||
if (details > 1)
|
||||
{
|
||||
b = msr->flags;
|
||||
ms_log (0, " flags: [%d%d%d%d%d%d%d%d] 8 bits\n",
|
||||
bit (b, 0x80), bit (b, 0x40), bit (b, 0x20), bit (b, 0x10),
|
||||
bit (b, 0x08), bit (b, 0x04), bit (b, 0x02), bit (b, 0x01));
|
||||
if (b & 0x01)
|
||||
ms_log (0, " [Bit 0] Calibration signals present\n");
|
||||
if (b & 0x02)
|
||||
ms_log (0, " [Bit 1] Time tag is questionable\n");
|
||||
if (b & 0x04)
|
||||
ms_log (0, " [Bit 2] Clock locked\n");
|
||||
if (b & 0x08)
|
||||
ms_log (0, " [Bit 3] Undefined bit set\n");
|
||||
if (b & 0x10)
|
||||
ms_log (0, " [Bit 4] Undefined bit set\n");
|
||||
if (b & 0x20)
|
||||
ms_log (0, " [Bit 5] Undefined bit set\n");
|
||||
if (b & 0x40)
|
||||
ms_log (0, " [Bit 6] Undefined bit set\n");
|
||||
if (b & 0x80)
|
||||
ms_log (0, " [Bit 7] Undefined bit set\n");
|
||||
}
|
||||
|
||||
ms_log (0, " CRC: 0x%0X\n", msr->crc);
|
||||
ms_log (0, " extra header length: %d bytes\n", msr->extralength);
|
||||
ms_log (0, " data payload length: %d bytes\n", msr->datalength);
|
||||
ms_log (0, " payload encoding: %s (val: %d)\n",
|
||||
(char *)ms_encodingstr (msr->encoding), msr->encoding);
|
||||
|
||||
if (details > 1 && msr->extralength > 0 && msr->extra)
|
||||
{
|
||||
ms_log (0, " extra headers:\n");
|
||||
mseh_print (msr, 16);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (0, "%s, %d, %d, %" PRId64 " samples, %-.10g Hz, %s\n",
|
||||
msr->sid, msr->pubversion, msr->reclen,
|
||||
msr->samplecnt, msr3_sampratehz(msr), time);
|
||||
}
|
||||
} /* End of msr3_print() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Resize data sample buffer of ::MS3Record to what is needed
|
||||
*
|
||||
* This routine should only be used if pre-allocation of memory, via
|
||||
* ::libmseed_prealloc_block_size, was enabled to allocate the buffer.
|
||||
*
|
||||
* @param[in] msr ::MS3Record to resize buffer
|
||||
*
|
||||
* @returns Return 0 on success, otherwise returns a libmseed error code.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
***************************************************************************/
|
||||
int
|
||||
msr3_resize_buffer (MS3Record *msr)
|
||||
{
|
||||
uint8_t samplesize = 0;
|
||||
size_t datasize;
|
||||
|
||||
if (!msr)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'msr'\n");
|
||||
return MS_GENERROR;
|
||||
}
|
||||
|
||||
samplesize = ms_samplesize(msr->sampletype);
|
||||
|
||||
if (samplesize && msr->datasamples && msr->numsamples > 0)
|
||||
{
|
||||
datasize = (size_t) msr->numsamples * samplesize;
|
||||
|
||||
if (msr->datasize > datasize)
|
||||
{
|
||||
msr->datasamples = libmseed_memory.realloc (msr->datasamples, datasize);
|
||||
|
||||
if (msr->datasamples == NULL)
|
||||
{
|
||||
ms_log (2, "%s: Cannot (re)allocate memory\n", msr->sid);
|
||||
return MS_GENERROR;
|
||||
}
|
||||
|
||||
msr->datasize = datasize;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* End of msr3_resize_buffer() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Calculate sample rate in samples/second (Hertz) for a given ::MS3Record
|
||||
*
|
||||
* @param[in] msr ::MS3Record to calculate sample rate for
|
||||
*
|
||||
* @returns Return sample rate in Hertz (samples per second)
|
||||
***************************************************************************/
|
||||
inline double
|
||||
msr3_sampratehz (const MS3Record *msr)
|
||||
{
|
||||
if (!msr)
|
||||
return 0.0;
|
||||
|
||||
if (msr->samprate < 0.0)
|
||||
return (-1.0 / msr->samprate);
|
||||
else
|
||||
return msr->samprate;
|
||||
} /* End of msr3_sampratehz() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Calculate data latency based on the host time
|
||||
*
|
||||
* Calculation is based on the time of the last sample in the record; in
|
||||
* other words, the difference between the host time and the time of
|
||||
* the last sample in the record.
|
||||
*
|
||||
* Double precision is returned, but the true precision is dependent
|
||||
* on the accuracy of the host system clock among other things.
|
||||
*
|
||||
* @param[in] msr ::MS3Record to calculate lactency for
|
||||
*
|
||||
* @returns seconds of latency or 0.0 on error (indistinguishable from
|
||||
* 0.0 latency).
|
||||
***************************************************************************/
|
||||
double
|
||||
msr3_host_latency (const MS3Record *msr)
|
||||
{
|
||||
double span = 0.0; /* Time covered by the samples */
|
||||
double epoch; /* Current epoch time */
|
||||
double latency = 0.0;
|
||||
time_t tv;
|
||||
|
||||
if (msr == NULL)
|
||||
return 0.0;
|
||||
|
||||
/* Calculate the time covered by the samples */
|
||||
if (msr->samprate > 0.0 && msr->samplecnt > 0)
|
||||
span = (1.0 / msr->samprate) * (msr->samplecnt - 1);
|
||||
|
||||
/* Grab UTC time according to the system clock */
|
||||
epoch = (double)time (&tv);
|
||||
|
||||
/* Now calculate the latency */
|
||||
latency = epoch - ((double)msr->starttime / NSTMODULUS) - span;
|
||||
|
||||
return latency;
|
||||
} /* End of msr3_host_latency() */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,722 @@
|
||||
/***********************************************************************
|
||||
* Routines for packing Text, INT_16, INT_32, FLOAT_32, FLOAT_64,
|
||||
* STEIM1 and STEIM2 data records.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
************************************************************************/
|
||||
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libmseed.h"
|
||||
#include "packdata.h"
|
||||
|
||||
/************************************************************************
|
||||
* msr_encode_text:
|
||||
*
|
||||
* Encode text data and place in supplied buffer.
|
||||
*
|
||||
* Return number of samples in output buffer on success, -1 on failure.
|
||||
************************************************************************/
|
||||
int
|
||||
msr_encode_text (char *input, int samplecount, char *output,
|
||||
int outputlength)
|
||||
{
|
||||
int length;
|
||||
|
||||
if (samplecount <= 0)
|
||||
return 0;
|
||||
|
||||
if (!input || !output || outputlength <= 0)
|
||||
return -1;
|
||||
|
||||
/* Determine minimum of input or output */
|
||||
length = (samplecount < outputlength) ? samplecount : outputlength;
|
||||
|
||||
memcpy (output, input, length);
|
||||
|
||||
return length;
|
||||
} /* End of msr_encode_text() */
|
||||
|
||||
/************************************************************************
|
||||
* msr_encode_int16:
|
||||
*
|
||||
* Encode 16-bit integer data from an array of 32-bit integers and
|
||||
* place in supplied buffer. Swap if requested.
|
||||
*
|
||||
* Return number of samples in output buffer on success, -1 on failure.
|
||||
************************************************************************/
|
||||
int
|
||||
msr_encode_int16 (int32_t *input, int samplecount, int16_t *output,
|
||||
int outputlength, int swapflag)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (samplecount <= 0)
|
||||
return 0;
|
||||
|
||||
if (!input || !output || outputlength <= 0)
|
||||
return -1;
|
||||
|
||||
for (idx = 0; idx < samplecount && outputlength >= (int)sizeof (int16_t); idx++)
|
||||
{
|
||||
output[idx] = (int16_t)input[idx];
|
||||
|
||||
if (swapflag)
|
||||
ms_gswap2 (&output[idx]);
|
||||
|
||||
outputlength -= sizeof (int16_t);
|
||||
}
|
||||
|
||||
return idx;
|
||||
} /* End of msr_encode_int16() */
|
||||
|
||||
/************************************************************************
|
||||
* msr_encode_int32:
|
||||
*
|
||||
* Encode 32-bit integer data from an array of 32-bit integers and
|
||||
* place in supplied buffer. Swap if requested.
|
||||
*
|
||||
* Return number of samples in output buffer on success, -1 on failure.
|
||||
************************************************************************/
|
||||
int
|
||||
msr_encode_int32 (int32_t *input, int samplecount, int32_t *output,
|
||||
int outputlength, int swapflag)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (samplecount <= 0)
|
||||
return 0;
|
||||
|
||||
if (!input || !output || outputlength <= 0)
|
||||
return -1;
|
||||
|
||||
for (idx = 0; idx < samplecount && outputlength >= (int)sizeof (int32_t); idx++)
|
||||
{
|
||||
output[idx] = input[idx];
|
||||
|
||||
if (swapflag)
|
||||
ms_gswap4 (&output[idx]);
|
||||
|
||||
outputlength -= sizeof (int32_t);
|
||||
}
|
||||
|
||||
return idx;
|
||||
} /* End of msr_encode_int32() */
|
||||
|
||||
/************************************************************************
|
||||
* msr_encode_float32:
|
||||
*
|
||||
* Encode 32-bit float data from an array of 32-bit floats and place
|
||||
* in supplied buffer. Swap if requested.
|
||||
*
|
||||
* Return number of samples in output buffer on success, -1 on failure.
|
||||
************************************************************************/
|
||||
int
|
||||
msr_encode_float32 (float *input, int samplecount, float *output,
|
||||
int outputlength, int swapflag)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (samplecount <= 0)
|
||||
return 0;
|
||||
|
||||
if (!input || !output || outputlength <= 0)
|
||||
return -1;
|
||||
|
||||
for (idx = 0; idx < samplecount && outputlength >= (int)sizeof (float); idx++)
|
||||
{
|
||||
output[idx] = input[idx];
|
||||
|
||||
if (swapflag)
|
||||
ms_gswap4 (&output[idx]);
|
||||
|
||||
outputlength -= sizeof (float);
|
||||
}
|
||||
|
||||
return idx;
|
||||
} /* End of msr_encode_float32() */
|
||||
|
||||
/************************************************************************
|
||||
* msr_encode_float64:
|
||||
*
|
||||
* Encode 64-bit float data from an array of 64-bit doubles and place
|
||||
* in supplied buffer. Swap if requested.
|
||||
*
|
||||
* Return number of samples in output buffer on success, -1 on failure.
|
||||
************************************************************************/
|
||||
int
|
||||
msr_encode_float64 (double *input, int samplecount, double *output,
|
||||
int outputlength, int swapflag)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (samplecount <= 0)
|
||||
return 0;
|
||||
|
||||
if (!input || !output || outputlength <= 0)
|
||||
return -1;
|
||||
|
||||
for (idx = 0; idx < samplecount && outputlength >= (int)sizeof (double); idx++)
|
||||
{
|
||||
output[idx] = input[idx];
|
||||
|
||||
if (swapflag)
|
||||
ms_gswap8 (&output[idx]);
|
||||
|
||||
outputlength -= sizeof (double);
|
||||
}
|
||||
|
||||
return idx;
|
||||
} /* End of msr_encode_float64() */
|
||||
|
||||
/* Macro to determine number of bits needed to represent VALUE in
|
||||
* the following bit widths: 4,5,6,8,10,15,16,30,32 and set RESULT. */
|
||||
#define BITWIDTH(VALUE, RESULT) \
|
||||
if (VALUE >= -8 && VALUE <= 7) \
|
||||
RESULT = 4; \
|
||||
else if (VALUE >= -16 && VALUE <= 15) \
|
||||
RESULT = 5; \
|
||||
else if (VALUE >= -32 && VALUE <= 31) \
|
||||
RESULT = 6; \
|
||||
else if (VALUE >= -128 && VALUE <= 127) \
|
||||
RESULT = 8; \
|
||||
else if (VALUE >= -512 && VALUE <= 511) \
|
||||
RESULT = 10; \
|
||||
else if (VALUE >= -16384 && VALUE <= 16383) \
|
||||
RESULT = 15; \
|
||||
else if (VALUE >= -32768 && VALUE <= 32767) \
|
||||
RESULT = 16; \
|
||||
else if (VALUE >= -536870912 && VALUE <= 536870911) \
|
||||
RESULT = 30; \
|
||||
else \
|
||||
RESULT = 32;
|
||||
|
||||
/************************************************************************
|
||||
* msr_encode_steim1:
|
||||
*
|
||||
* Encode Steim1 data frames from an array of 32-bit integers and
|
||||
* place in supplied buffer. Swap if requested.
|
||||
*
|
||||
* diff0 is the first difference in the sequence and relates the first
|
||||
* sample to the sample previous to it (not available to this
|
||||
* function). It should be set to 0 if this value is not known.
|
||||
*
|
||||
* Return number of samples in output buffer on success, -1 on failure.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
************************************************************************/
|
||||
int
|
||||
msr_encode_steim1 (int32_t *input, int samplecount, int32_t *output,
|
||||
int outputlength, int32_t diff0, uint16_t *byteswritten,
|
||||
int swapflag)
|
||||
{
|
||||
int32_t *frameptr; /* Frame pointer in output */
|
||||
int32_t *Xnp = NULL; /* Reverse integration constant, aka last sample */
|
||||
int32_t diffs[4];
|
||||
int32_t bitwidth[4];
|
||||
int diffcount = 0;
|
||||
int inputidx = 0;
|
||||
int outputsamples = 0;
|
||||
int maxframes = outputlength / 64;
|
||||
int packedsamples = 0;
|
||||
int frameidx;
|
||||
int startnibble;
|
||||
int widx;
|
||||
int idx;
|
||||
|
||||
union dword {
|
||||
int8_t d8[4];
|
||||
int16_t d16[2];
|
||||
int32_t d32;
|
||||
} * word;
|
||||
|
||||
if (samplecount <= 0)
|
||||
return 0;
|
||||
|
||||
if (!input || !output || outputlength <= 0)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'input', 'output' or 'outputlength' <= 0\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, "Encoding Steim1 frames, samples: %d, max frames: %d, swapflag: %d\n",
|
||||
samplecount, maxframes, swapflag);
|
||||
#endif
|
||||
|
||||
/* Add first difference to buffers */
|
||||
diffs[0] = diff0;
|
||||
BITWIDTH (diffs[0], bitwidth[0]);
|
||||
diffcount = 1;
|
||||
|
||||
for (frameidx = 0; frameidx < maxframes && outputsamples < samplecount; frameidx++)
|
||||
{
|
||||
frameptr = output + (16 * frameidx);
|
||||
|
||||
/* Set 64-byte frame to 0's */
|
||||
memset (frameptr, 0, 64);
|
||||
|
||||
/* Save forward integration constant (X0), pointer to reverse integration constant (Xn)
|
||||
* and set the starting nibble index depending on frame. */
|
||||
if (frameidx == 0)
|
||||
{
|
||||
frameptr[1] = input[0];
|
||||
|
||||
if (swapflag)
|
||||
ms_gswap4 (&frameptr[1]);
|
||||
|
||||
Xnp = &frameptr[2];
|
||||
|
||||
startnibble = 3; /* First frame: skip nibbles, X0, and Xn */
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, "Frame %d: X0=%d\n", frameidx, input[0]);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
startnibble = 1; /* Subsequent frames: skip nibbles */
|
||||
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, "Frame %d\n", frameidx);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (widx = startnibble; widx < 16 && outputsamples < samplecount; widx++)
|
||||
{
|
||||
if (diffcount < 4)
|
||||
{
|
||||
/* Shift diffs and related bit widths to beginning of buffers */
|
||||
for (idx = 0; idx < diffcount; idx++)
|
||||
{
|
||||
diffs[idx] = diffs[packedsamples + idx];
|
||||
bitwidth[idx] = bitwidth[packedsamples + idx];
|
||||
}
|
||||
|
||||
/* Add new diffs and determine bit width needed to represent */
|
||||
for (idx = diffcount; idx < 4 && inputidx < (samplecount - 1); idx++, inputidx++)
|
||||
{
|
||||
diffs[idx] = *(input + inputidx + 1) - *(input + inputidx);
|
||||
BITWIDTH (diffs[idx], bitwidth[idx]);
|
||||
diffcount++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine optimal packing by checking, in-order:
|
||||
* 4 x 8-bit differences
|
||||
* 2 x 16-bit differences
|
||||
* 1 x 32-bit difference */
|
||||
|
||||
word = (union dword *)&frameptr[widx];
|
||||
packedsamples = 0;
|
||||
|
||||
/* 4 x 8-bit differences */
|
||||
if (diffcount == 4 &&
|
||||
bitwidth[0] <= 8 && bitwidth[1] <= 8 &&
|
||||
bitwidth[2] <= 8 && bitwidth[3] <= 8)
|
||||
{
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, " W%02d: 01=4x8b %d %d %d %d\n",
|
||||
widx, diffs[0], diffs[1], diffs[2], diffs[3]);
|
||||
#endif
|
||||
|
||||
word->d8[0] = diffs[0];
|
||||
word->d8[1] = diffs[1];
|
||||
word->d8[2] = diffs[2];
|
||||
word->d8[3] = diffs[3];
|
||||
|
||||
/* 2-bit nibble is 0b01 (0x1) */
|
||||
frameptr[0] |= 0x1ul << (30 - 2 * widx);
|
||||
|
||||
packedsamples = 4;
|
||||
}
|
||||
/* 2 x 16-bit differences */
|
||||
else if (diffcount >= 2 &&
|
||||
bitwidth[0] <= 16 && bitwidth[1] <= 16)
|
||||
{
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, " W%02d: 2=2x16b %d %d\n", widx, diffs[0], diffs[1]);
|
||||
#endif
|
||||
|
||||
word->d16[0] = diffs[0];
|
||||
word->d16[1] = diffs[1];
|
||||
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap2 (&word->d16[0]);
|
||||
ms_gswap2 (&word->d16[1]);
|
||||
}
|
||||
|
||||
/* 2-bit nibble is 0b10 (0x2) */
|
||||
frameptr[0] |= 0x2ul << (30 - 2 * widx);
|
||||
|
||||
packedsamples = 2;
|
||||
}
|
||||
/* 1 x 32-bit difference */
|
||||
else
|
||||
{
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, " W%02d: 3=1x32b %d\n", widx, diffs[0]);
|
||||
#endif
|
||||
|
||||
frameptr[widx] = diffs[0];
|
||||
|
||||
if (swapflag)
|
||||
ms_gswap4 (&frameptr[widx]);
|
||||
|
||||
/* 2-bit nibble is 0b11 (0x3) */
|
||||
frameptr[0] |= 0x3ul << (30 - 2 * widx);
|
||||
|
||||
packedsamples = 1;
|
||||
}
|
||||
|
||||
diffcount -= packedsamples;
|
||||
outputsamples += packedsamples;
|
||||
} /* Done with words in frame */
|
||||
|
||||
/* Swap word with nibbles */
|
||||
if (swapflag)
|
||||
ms_gswap4 (&frameptr[0]);
|
||||
} /* Done with frames */
|
||||
|
||||
/* Set Xn (reverse integration constant) in first frame to last sample */
|
||||
if (Xnp)
|
||||
*Xnp = *(input + outputsamples - 1);
|
||||
if (swapflag)
|
||||
ms_gswap4 (Xnp);
|
||||
|
||||
if (byteswritten)
|
||||
*byteswritten = frameidx * 64;
|
||||
|
||||
return outputsamples;
|
||||
} /* End of msr_encode_steim1() */
|
||||
|
||||
/************************************************************************
|
||||
* msr_encode_steim2:
|
||||
*
|
||||
* Encode Steim2 data frames from an array of 32-bit integers and
|
||||
* place in supplied buffer. Swap if requested.
|
||||
*
|
||||
* diff0 is the first difference in the sequence and relates the first
|
||||
* sample to the sample previous to it (not available to this
|
||||
* function). It should be set to 0 if this value is not known.
|
||||
*
|
||||
* Return number of samples in output buffer on success, -1 on failure.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
************************************************************************/
|
||||
int
|
||||
msr_encode_steim2 (int32_t *input, int samplecount, int32_t *output,
|
||||
int outputlength, int32_t diff0, uint16_t *byteswritten,
|
||||
const char *sid, int swapflag)
|
||||
{
|
||||
uint32_t *frameptr; /* Frame pointer in output */
|
||||
int32_t *Xnp = NULL; /* Reverse integration constant, aka last sample */
|
||||
int32_t diffs[7];
|
||||
int32_t bitwidth[7];
|
||||
int diffcount = 0;
|
||||
int inputidx = 0;
|
||||
int outputsamples = 0;
|
||||
int maxframes = outputlength / 64;
|
||||
int packedsamples = 0;
|
||||
int frameidx;
|
||||
int startnibble;
|
||||
int widx;
|
||||
int idx;
|
||||
|
||||
union dword {
|
||||
int8_t d8[4];
|
||||
int16_t d16[2];
|
||||
int32_t d32;
|
||||
} * word;
|
||||
|
||||
if (samplecount <= 0)
|
||||
return 0;
|
||||
|
||||
if (!input || !output || outputlength <= 0)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'input', 'output' or 'outputlength' <= 0\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, "Encoding Steim2 frames, samples: %d, max frames: %d, swapflag: %d\n",
|
||||
samplecount, maxframes, swapflag);
|
||||
#endif
|
||||
|
||||
/* Add first difference to buffers */
|
||||
diffs[0] = diff0;
|
||||
BITWIDTH (diffs[0], bitwidth[0]);
|
||||
diffcount = 1;
|
||||
|
||||
for (frameidx = 0; frameidx < maxframes && outputsamples < samplecount; frameidx++)
|
||||
{
|
||||
frameptr = (uint32_t *)output + (16 * frameidx);
|
||||
|
||||
/* Set 64-byte frame to 0's */
|
||||
memset (frameptr, 0, 64);
|
||||
|
||||
/* Save forward integration constant (X0), pointer to reverse integration constant (Xn)
|
||||
* and set the starting nibble index depending on frame. */
|
||||
if (frameidx == 0)
|
||||
{
|
||||
frameptr[1] = input[0];
|
||||
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, "Frame %d: X0=%d\n", frameidx, input[0]);
|
||||
#endif
|
||||
|
||||
if (swapflag)
|
||||
ms_gswap4 (&frameptr[1]);
|
||||
|
||||
Xnp = (int32_t *)&frameptr[2];
|
||||
|
||||
startnibble = 3; /* First frame: skip nibbles, X0, and Xn */
|
||||
}
|
||||
else
|
||||
{
|
||||
startnibble = 1; /* Subsequent frames: skip nibbles */
|
||||
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, "Frame %d\n", frameidx);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (widx = startnibble; widx < 16 && outputsamples < samplecount; widx++)
|
||||
{
|
||||
if (diffcount < 7)
|
||||
{
|
||||
/* Shift diffs and related bit widths to beginning of buffers */
|
||||
for (idx = 0; idx < diffcount; idx++)
|
||||
{
|
||||
diffs[idx] = diffs[packedsamples + idx];
|
||||
bitwidth[idx] = bitwidth[packedsamples + idx];
|
||||
}
|
||||
|
||||
/* Add new diffs and determine bit width needed to represent */
|
||||
for (idx = diffcount; idx < 7 && inputidx < (samplecount - 1); idx++, inputidx++)
|
||||
{
|
||||
diffs[idx] = *(input + inputidx + 1) - *(input + inputidx);
|
||||
BITWIDTH (diffs[idx], bitwidth[idx]);
|
||||
diffcount++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine optimal packing by checking, in-order:
|
||||
* 7 x 4-bit differences
|
||||
* 6 x 5-bit differences
|
||||
* 5 x 6-bit differences
|
||||
* 4 x 8-bit differences
|
||||
* 3 x 10-bit differences
|
||||
* 2 x 15-bit differences
|
||||
* 1 x 30-bit difference */
|
||||
|
||||
packedsamples = 0;
|
||||
|
||||
/* 7 x 4-bit differences */
|
||||
if (diffcount == 7 && bitwidth[0] <= 4 &&
|
||||
bitwidth[1] <= 4 && bitwidth[2] <= 4 && bitwidth[3] <= 4 &&
|
||||
bitwidth[4] <= 4 && bitwidth[5] <= 4 && bitwidth[6] <= 4)
|
||||
{
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, " W%02d: 11,10=7x4b %d %d %d %d %d %d %d\n",
|
||||
widx, diffs[0], diffs[1], diffs[2], diffs[3], diffs[4], diffs[5], diffs[6]);
|
||||
#endif
|
||||
|
||||
/* Mask the values, shift to proper location and set in word */
|
||||
frameptr[widx] = ((uint32_t)diffs[6] & 0xFul);
|
||||
frameptr[widx] |= ((uint32_t)diffs[5] & 0xFul) << 4;
|
||||
frameptr[widx] |= ((uint32_t)diffs[4] & 0xFul) << 8;
|
||||
frameptr[widx] |= ((uint32_t)diffs[3] & 0xFul) << 12;
|
||||
frameptr[widx] |= ((uint32_t)diffs[2] & 0xFul) << 16;
|
||||
frameptr[widx] |= ((uint32_t)diffs[1] & 0xFul) << 20;
|
||||
frameptr[widx] |= ((uint32_t)diffs[0] & 0xFul) << 24;
|
||||
|
||||
/* 2-bit decode nibble is 0b10 (0x2) */
|
||||
frameptr[widx] |= 0x2ul << 30;
|
||||
|
||||
/* 2-bit nibble is 0b11 (0x3) */
|
||||
frameptr[0] |= 0x3ul << (30 - 2 * widx);
|
||||
|
||||
packedsamples = 7;
|
||||
}
|
||||
/* 6 x 5-bit differences */
|
||||
else if (diffcount >= 6 &&
|
||||
bitwidth[0] <= 5 && bitwidth[1] <= 5 && bitwidth[2] <= 5 &&
|
||||
bitwidth[3] <= 5 && bitwidth[4] <= 5 && bitwidth[5] <= 5)
|
||||
{
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, " W%02d: 11,01=6x5b %d %d %d %d %d %d\n",
|
||||
widx, diffs[0], diffs[1], diffs[2], diffs[3], diffs[4], diffs[5]);
|
||||
#endif
|
||||
|
||||
/* Mask the values, shift to proper location and set in word */
|
||||
frameptr[widx] = ((uint32_t)diffs[5] & 0x1Ful);
|
||||
frameptr[widx] |= ((uint32_t)diffs[4] & 0x1Ful) << 5;
|
||||
frameptr[widx] |= ((uint32_t)diffs[3] & 0x1Ful) << 10;
|
||||
frameptr[widx] |= ((uint32_t)diffs[2] & 0x1Ful) << 15;
|
||||
frameptr[widx] |= ((uint32_t)diffs[1] & 0x1Ful) << 20;
|
||||
frameptr[widx] |= ((uint32_t)diffs[0] & 0x1Ful) << 25;
|
||||
|
||||
/* 2-bit decode nibble is 0b01 (0x1) */
|
||||
frameptr[widx] |= 0x1ul << 30;
|
||||
|
||||
/* 2-bit nibble is 0b11 (0x3) */
|
||||
frameptr[0] |= 0x3ul << (30 - 2 * widx);
|
||||
|
||||
packedsamples = 6;
|
||||
}
|
||||
/* 5 x 6-bit differences */
|
||||
else if (diffcount >= 5 &&
|
||||
bitwidth[0] <= 6 && bitwidth[1] <= 6 && bitwidth[2] <= 6 &&
|
||||
bitwidth[3] <= 6 && bitwidth[4] <= 6)
|
||||
{
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, " W%02d: 11,00=5x6b %d %d %d %d %d\n",
|
||||
widx, diffs[0], diffs[1], diffs[2], diffs[3], diffs[4]);
|
||||
#endif
|
||||
|
||||
/* Mask the values, shift to proper location and set in word */
|
||||
frameptr[widx] = ((uint32_t)diffs[4] & 0x3Ful);
|
||||
frameptr[widx] |= ((uint32_t)diffs[3] & 0x3Ful) << 6;
|
||||
frameptr[widx] |= ((uint32_t)diffs[2] & 0x3Ful) << 12;
|
||||
frameptr[widx] |= ((uint32_t)diffs[1] & 0x3Ful) << 18;
|
||||
frameptr[widx] |= ((uint32_t)diffs[0] & 0x3Ful) << 24;
|
||||
|
||||
/* 2-bit decode nibble is 0b00, nothing to set */
|
||||
|
||||
/* 2-bit nibble is 0b11 (0x3) */
|
||||
frameptr[0] |= 0x3ul << (30 - 2 * widx);
|
||||
|
||||
packedsamples = 5;
|
||||
}
|
||||
/* 4 x 8-bit differences */
|
||||
else if (diffcount >= 4 &&
|
||||
bitwidth[0] <= 8 && bitwidth[1] <= 8 &&
|
||||
bitwidth[2] <= 8 && bitwidth[3] <= 8)
|
||||
{
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, " W%02d: 01=4x8b %d %d %d %d\n",
|
||||
widx, diffs[0], diffs[1], diffs[2], diffs[3]);
|
||||
#endif
|
||||
|
||||
word = (union dword *)&frameptr[widx];
|
||||
|
||||
word->d8[0] = diffs[0];
|
||||
word->d8[1] = diffs[1];
|
||||
word->d8[2] = diffs[2];
|
||||
word->d8[3] = diffs[3];
|
||||
|
||||
/* 2-bit nibble is 0b01, only need to set 2nd bit */
|
||||
frameptr[0] |= 0x1ul << (30 - 2 * widx);
|
||||
|
||||
packedsamples = 4;
|
||||
}
|
||||
/* 3 x 10-bit differences */
|
||||
else if (diffcount >= 3 &&
|
||||
bitwidth[0] <= 10 && bitwidth[1] <= 10 && bitwidth[2] <= 10)
|
||||
{
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, " W%02d: 10,11=3x10b %d %d %d\n",
|
||||
widx, diffs[0], diffs[1], diffs[2]);
|
||||
#endif
|
||||
|
||||
/* Mask the values, shift to proper location and set in word */
|
||||
frameptr[widx] = ((uint32_t)diffs[2] & 0x3FFul);
|
||||
frameptr[widx] |= ((uint32_t)diffs[1] & 0x3FFul) << 10;
|
||||
frameptr[widx] |= ((uint32_t)diffs[0] & 0x3FFul) << 20;
|
||||
|
||||
/* 2-bit decode nibble is 0b11 (0x3) */
|
||||
frameptr[widx] |= 0x3ul << 30;
|
||||
|
||||
/* 2-bit nibble is 0b10 (0x2) */
|
||||
frameptr[0] |= 0x2ul << (30 - 2 * widx);
|
||||
|
||||
packedsamples = 3;
|
||||
}
|
||||
/* 2 x 15-bit differences */
|
||||
else if (diffcount >= 2 &&
|
||||
bitwidth[0] <= 15 && bitwidth[1] <= 15)
|
||||
{
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, " W%02d: 10,10=2x15b %d %d\n",
|
||||
widx, diffs[0], diffs[1]);
|
||||
#endif
|
||||
|
||||
/* Mask the values, shift to proper location and set in word */
|
||||
frameptr[widx] = ((uint32_t)diffs[1] & 0x7FFFul);
|
||||
frameptr[widx] |= ((uint32_t)diffs[0] & 0x7FFFul) << 15;
|
||||
|
||||
/* 2-bit decode nibble is 0b10 (0x2) */
|
||||
frameptr[widx] |= 0x2ul << 30;
|
||||
|
||||
/* 2-bit nibble is 0b10 (0x2) */
|
||||
frameptr[0] |= 0x2ul << (30 - 2 * widx);
|
||||
|
||||
packedsamples = 2;
|
||||
}
|
||||
/* 1 x 30-bit difference */
|
||||
else if (diffcount >= 1 &&
|
||||
bitwidth[0] <= 30)
|
||||
{
|
||||
#if ENCODE_DEBUG
|
||||
ms_log (0, " W%02d: 10,01=1x30b %d\n",
|
||||
widx, diffs[0]);
|
||||
#endif
|
||||
|
||||
/* Mask the value and set in word */
|
||||
frameptr[widx] = ((uint32_t)diffs[0] & 0x3FFFFFFFul);
|
||||
|
||||
/* 2-bit decode nibble is 0b01 (0x1) */
|
||||
frameptr[widx] |= 0x1ul << 30;
|
||||
|
||||
/* 2-bit nibble is 0b10 (0x2) */
|
||||
frameptr[0] |= 0x2ul << (30 - 2 * widx);
|
||||
|
||||
packedsamples = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (2, "%s: Unable to represent difference in <= 30 bits\n", sid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Swap encoded word except for 4x8-bit samples */
|
||||
if (swapflag && packedsamples != 4)
|
||||
ms_gswap4 (&frameptr[widx]);
|
||||
|
||||
diffcount -= packedsamples;
|
||||
outputsamples += packedsamples;
|
||||
} /* Done with words in frame */
|
||||
|
||||
/* Swap word with nibbles */
|
||||
if (swapflag)
|
||||
ms_gswap4 (&frameptr[0]);
|
||||
} /* Done with frames */
|
||||
|
||||
/* Set Xn (reverse integration constant) in first frame to last sample */
|
||||
if (Xnp)
|
||||
*Xnp = *(input + outputsamples - 1);
|
||||
if (swapflag)
|
||||
ms_gswap4 (Xnp);
|
||||
|
||||
if (byteswritten)
|
||||
*byteswritten = frameidx * 64;
|
||||
|
||||
return outputsamples;
|
||||
} /* End of msr_encode_steim2() */
|
@ -0,0 +1,58 @@
|
||||
/***************************************************************************
|
||||
* Interface declarations for the miniSEED packing routines in
|
||||
* packdata.c
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef PACKDATA_H
|
||||
#define PACKDATA_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "libmseed.h"
|
||||
|
||||
#define STEIM1_FRAME_MAX_SAMPLES 60
|
||||
#define STEIM2_FRAME_MAX_SAMPLES 105
|
||||
|
||||
/* Control for printing debugging information, declared in packdata.c */
|
||||
extern int libmseed_encodedebug;
|
||||
|
||||
extern int msr_encode_text (char *input, int samplecount, char *output,
|
||||
int outputlength);
|
||||
extern int msr_encode_int16 (int32_t *input, int samplecount, int16_t *output,
|
||||
int outputlength, int swapflag);
|
||||
extern int msr_encode_int32 (int32_t *input, int samplecount, int32_t *output,
|
||||
int outputlength, int swapflag);
|
||||
extern int msr_encode_float32 (float *input, int samplecount, float *output,
|
||||
int outputlength, int swapflag);
|
||||
extern int msr_encode_float64 (double *input, int samplecount, double *output,
|
||||
int outputlength, int swapflag);
|
||||
extern int msr_encode_steim1 (int32_t *input, int samplecount, int32_t *output,
|
||||
int outputlength, int32_t diff0, uint16_t *byteswritten,
|
||||
int swapflag);
|
||||
extern int msr_encode_steim2 (int32_t *input, int samplecount, int32_t *output,
|
||||
int outputlength, int32_t diff0, uint16_t *byteswritten,
|
||||
const char *sid, int swapflag);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,927 @@
|
||||
/***************************************************************************
|
||||
* Generic routines to manage selection lists.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "libmseed.h"
|
||||
|
||||
static int ms_isinteger (const char *string);
|
||||
static int ms_globmatch (const char *string, const char *pattern);
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Test the specified parameters for a matching selection entry
|
||||
*
|
||||
* Search the ::MS3Selections for an entry matching the provided
|
||||
* parameters. The ::MS3Selections.sidpattern may contain globbing
|
||||
* characters. The ::MS3Selections.timewindows many contain start and
|
||||
* end times set to ::NSTUNSET to denote "open" times.
|
||||
*
|
||||
* Positive matching requires:
|
||||
* @parblock
|
||||
* -# glob match of sid against sidpattern in selection
|
||||
* -# time window intersection with range in selection
|
||||
* -# equal pubversion if selection pubversion > 0
|
||||
* @endparblock
|
||||
*
|
||||
* @param[in] selections ::MS3Selections to search
|
||||
* @param[in] sid Source ID to match
|
||||
* @param[in] starttime Start time to match
|
||||
* @param[in] endtime End time to match
|
||||
* @param[in] pubversion Publication version to match
|
||||
* @param[out] ppselecttime Pointer-to-pointer to return the matching ::MS3SelectTime entry
|
||||
*
|
||||
* @returns A pointer to matching ::MS3Selections entry successful
|
||||
* match and NULL for no match or error.
|
||||
***************************************************************************/
|
||||
const MS3Selections *
|
||||
ms3_matchselect (const MS3Selections *selections, const char *sid, nstime_t starttime,
|
||||
nstime_t endtime, int pubversion, const MS3SelectTime **ppselecttime)
|
||||
{
|
||||
const MS3Selections *findsl = NULL;
|
||||
const MS3SelectTime *findst = NULL;
|
||||
const MS3SelectTime *matchst = NULL;
|
||||
|
||||
if (selections)
|
||||
{
|
||||
findsl = selections;
|
||||
while (findsl)
|
||||
{
|
||||
if (ms_globmatch (sid, findsl->sidpattern))
|
||||
{
|
||||
if (findsl->pubversion > 0 && findsl->pubversion != pubversion)
|
||||
{
|
||||
findsl = findsl->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If no time selection, this is a match */
|
||||
if (!findsl->timewindows)
|
||||
{
|
||||
if (ppselecttime)
|
||||
*ppselecttime = NULL;
|
||||
|
||||
return findsl;
|
||||
}
|
||||
|
||||
/* Otherwise, search the time selections */
|
||||
findst = findsl->timewindows;
|
||||
while (findst)
|
||||
{
|
||||
if (starttime != NSTERROR && starttime != NSTUNSET &&
|
||||
findst->starttime != NSTERROR && findst->starttime != NSTUNSET &&
|
||||
(starttime < findst->starttime && !(starttime <= findst->starttime && endtime >= findst->starttime)))
|
||||
{
|
||||
findst = findst->next;
|
||||
continue;
|
||||
}
|
||||
else if (endtime != NSTERROR && endtime != NSTUNSET &&
|
||||
findst->endtime != NSTERROR && findst->endtime != NSTUNSET &&
|
||||
(endtime > findst->endtime && !(starttime <= findst->endtime && endtime >= findst->endtime)))
|
||||
{
|
||||
findst = findst->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
matchst = findst;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchst)
|
||||
break;
|
||||
else
|
||||
findsl = findsl->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (ppselecttime)
|
||||
*ppselecttime = matchst;
|
||||
|
||||
return (matchst) ? findsl : NULL;
|
||||
} /* End of ms3_matchselect() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Test the ::MS3Record for a matching selection entry
|
||||
*
|
||||
* Search the ::MS3Selections for an entry matching the provided
|
||||
* parameters.
|
||||
*
|
||||
* Positive matching requires:
|
||||
* @parblock
|
||||
* -# glob match of sid against sidpattern in selection
|
||||
* -# time window intersection with range in selection
|
||||
* -# equal pubversion if selection pubversion > 0
|
||||
* @endparblock
|
||||
*
|
||||
* @param[in] selections ::MS3Selections to search
|
||||
* @param[in] msr ::MS3Record to match against selections
|
||||
* @param[out] ppselecttime Pointer-to-pointer to return the matching ::MS3SelectTime entry
|
||||
*
|
||||
* @returns A pointer to matching ::MS3Selections entry successful
|
||||
* match and NULL for no match or error.
|
||||
***************************************************************************/
|
||||
const MS3Selections *
|
||||
msr3_matchselect (const MS3Selections *selections, const MS3Record *msr,
|
||||
const MS3SelectTime **ppselecttime)
|
||||
{
|
||||
nstime_t endtime;
|
||||
|
||||
if (!selections || !msr)
|
||||
return NULL;
|
||||
|
||||
endtime = msr3_endtime (msr);
|
||||
|
||||
return ms3_matchselect (selections, msr->sid, msr->starttime, endtime,
|
||||
msr->pubversion, ppselecttime);
|
||||
} /* End of msr3_matchselect() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Add selection parameters to selection list.
|
||||
*
|
||||
* The \a sidpattern may contain globbing characters.
|
||||
*
|
||||
* The \a starttime and \a endtime may be set to ::NSTUNSET to denote
|
||||
* "open" times.
|
||||
*
|
||||
* The \a pubversion may be set to 0 to match any publication
|
||||
* version.
|
||||
*
|
||||
* @param[in] ppselections ::MS3Selections to add new selection to
|
||||
* @param[in] sidpattern Source ID pattern, may contain globbing characters
|
||||
* @param[in] starttime Start time for selection, ::NSTUNSET for open
|
||||
* @param[in] endtime End time for selection, ::NSTUNSET for open
|
||||
* @param[in] pubversion Publication version for selection, 0 for any
|
||||
*
|
||||
* @returns 0 on success and -1 on error.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
***************************************************************************/
|
||||
int
|
||||
ms3_addselect (MS3Selections **ppselections, const char *sidpattern,
|
||||
nstime_t starttime, nstime_t endtime, uint8_t pubversion)
|
||||
{
|
||||
MS3Selections *newsl = NULL;
|
||||
MS3SelectTime *newst = NULL;
|
||||
|
||||
if (!ppselections || !sidpattern)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'ppselections' or 'sidpattern'\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate new SelectTime and populate */
|
||||
if (!(newst = (MS3SelectTime *)libmseed_memory.malloc (sizeof (MS3SelectTime))))
|
||||
{
|
||||
ms_log (2, "Cannot allocate memory\n");
|
||||
return -1;
|
||||
}
|
||||
memset (newst, 0, sizeof (MS3SelectTime));
|
||||
|
||||
newst->starttime = starttime;
|
||||
newst->endtime = endtime;
|
||||
|
||||
/* Add new Selections struct to begining of list */
|
||||
if (!*ppselections)
|
||||
{
|
||||
/* Allocate new Selections and populate */
|
||||
if (!(newsl = (MS3Selections *)libmseed_memory.malloc (sizeof (MS3Selections))))
|
||||
{
|
||||
ms_log (2, "Cannot allocate memory\n");
|
||||
return -1;
|
||||
}
|
||||
memset (newsl, 0, sizeof (MS3Selections));
|
||||
|
||||
strncpy (newsl->sidpattern, sidpattern, sizeof (newsl->sidpattern));
|
||||
newsl->sidpattern[sizeof (newsl->sidpattern) - 1] = '\0';
|
||||
newsl->pubversion = pubversion;
|
||||
|
||||
/* Add new MS3SelectTime struct as first in list */
|
||||
*ppselections = newsl;
|
||||
newsl->timewindows = newst;
|
||||
}
|
||||
else
|
||||
{
|
||||
MS3Selections *findsl = *ppselections;
|
||||
MS3Selections *matchsl = 0;
|
||||
|
||||
/* Search for matching MS3Selections entry */
|
||||
while (findsl)
|
||||
{
|
||||
if (!strcmp (findsl->sidpattern, sidpattern) && findsl->pubversion == pubversion)
|
||||
{
|
||||
matchsl = findsl;
|
||||
break;
|
||||
}
|
||||
|
||||
findsl = findsl->next;
|
||||
}
|
||||
|
||||
if (matchsl)
|
||||
{
|
||||
/* Add time window selection to beginning of window list */
|
||||
newst->next = matchsl->timewindows;
|
||||
matchsl->timewindows = newst;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Allocate new MS3Selections and populate */
|
||||
if (!(newsl = (MS3Selections *)libmseed_memory.malloc (sizeof (MS3Selections))))
|
||||
{
|
||||
ms_log (2, "Cannot allocate memory\n");
|
||||
return -1;
|
||||
}
|
||||
memset (newsl, 0, sizeof (MS3Selections));
|
||||
|
||||
strncpy (newsl->sidpattern, sidpattern, sizeof (newsl->sidpattern));
|
||||
newsl->sidpattern[sizeof (newsl->sidpattern) - 1] = '\0';
|
||||
newsl->pubversion = pubversion;
|
||||
|
||||
/* Add new MS3Selections to beginning of list */
|
||||
newsl->next = *ppselections;
|
||||
*ppselections = newsl;
|
||||
newsl->timewindows = newst;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* End of ms3_addselect() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Add selection parameters to a selection list based on
|
||||
* separate source name codes
|
||||
*
|
||||
* The \a network, \a station, \a location, and \a channel arguments may
|
||||
* contain globbing parameters.
|
||||
|
||||
* The \a starttime and \a endtime may be set to ::NSTUNSET to denote
|
||||
* "open" times.
|
||||
*
|
||||
* The \a pubversion may be set to 0 to match any publication
|
||||
* version.
|
||||
*
|
||||
* If any of the naming parameters are not supplied (pointer is NULL)
|
||||
* a wildcard for all matches is substituted.
|
||||
*
|
||||
* As a special case, if the location code (loc) is set to \c "--" to
|
||||
* match an empty location code it will be translated to an empty string
|
||||
* to match libmseed's notation.
|
||||
*
|
||||
* @param[in] ppselections ::MS3Selections to add new selection to
|
||||
* @param[in] network Network code, may contain globbing characters
|
||||
* @param[in] station Statoin code, may contain globbing characters
|
||||
* @param[in] location Location code, may contain globbing characters
|
||||
* @param[in] channel channel code, may contain globbing characters
|
||||
* @param[in] starttime Start time for selection, ::NSTUNSET for open
|
||||
* @param[in] endtime End time for selection, ::NSTUNSET for open
|
||||
* @param[in] pubversion Publication version for selection, 0 for any
|
||||
*
|
||||
* @return 0 on success and -1 on error.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
***************************************************************************/
|
||||
int
|
||||
ms3_addselect_comp (MS3Selections **ppselections, char *network, char *station,
|
||||
char *location, char *channel, nstime_t starttime,
|
||||
nstime_t endtime, uint8_t pubversion)
|
||||
{
|
||||
char sidpattern[100];
|
||||
char selnet[20];
|
||||
char selsta[20];
|
||||
char selloc[20];
|
||||
char selchan[20];
|
||||
|
||||
if (!ppselections)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'ppselections'\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (network)
|
||||
{
|
||||
strncpy (selnet, network, sizeof (selnet));
|
||||
selnet[sizeof (selnet) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (selnet, "*");
|
||||
}
|
||||
|
||||
if (station)
|
||||
{
|
||||
strncpy (selsta, station, sizeof (selsta));
|
||||
selsta[sizeof (selsta) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (selsta, "*");
|
||||
}
|
||||
|
||||
if (location)
|
||||
{
|
||||
/* Test for special case blank location ID */
|
||||
if (!strcmp (location, "--"))
|
||||
{
|
||||
selloc[0] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy (selloc, location, sizeof (selloc));
|
||||
selloc[sizeof (selloc) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (selloc, "*");
|
||||
}
|
||||
|
||||
if (channel)
|
||||
{
|
||||
/* Convert a 3-character SEED 2.x channel code to an extended code */
|
||||
if (ms_globmatch (channel, "[?*a-zA-Z0-9][?*a-zA-Z0-9][?*a-zA-Z0-9]"))
|
||||
{
|
||||
ms_seedchan2xchan (selchan, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy (selchan, channel, sizeof (selchan));
|
||||
selchan[sizeof (selchan) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (selchan, "*");
|
||||
}
|
||||
|
||||
/* Create the source identifier globbing match for this entry */
|
||||
if (ms_nslc2sid (sidpattern, sizeof (sidpattern), 0,
|
||||
selnet, selsta, selloc, selchan) < 0)
|
||||
return -1;
|
||||
|
||||
/* Add selection to list */
|
||||
if (ms3_addselect (ppselections, sidpattern, starttime, endtime, pubversion))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
} /* End of ms3_addselect_comp() */
|
||||
|
||||
#define MAX_SELECTION_FIELDS 8
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Read data selections from a file
|
||||
*
|
||||
* Selections from a file are added to the specified selections list.
|
||||
* On errors this routine will leave allocated memory unreachable
|
||||
* (leaked), it is expected that this is a program failing condition.
|
||||
*
|
||||
* As a special case if the filename is "-", selection lines will be
|
||||
* read from stdin.
|
||||
*
|
||||
* Each line of the file contains a single selection and may be one of
|
||||
* these two line formats:
|
||||
* @code
|
||||
* SourceID [Starttime [Endtime [Pubversion]]]
|
||||
* @endcode
|
||||
* or
|
||||
* @code
|
||||
* Network Station Location Channel [Pubversion [Starttime [Endtime]]]
|
||||
* @endcode
|
||||
*
|
||||
* The \c Starttime and \c Endtime values must be in a form recognized
|
||||
* by ms_timestr2nstime() and include a full date (i.e. just a year is
|
||||
* not allowed).
|
||||
*
|
||||
* In the latter version, if the "Channel" field is a SEED 2.x channel
|
||||
* (3-characters) it will automatically be converted into extended
|
||||
* channel form (band_source_subsource).
|
||||
*
|
||||
* In the latter version, the "Pubversion" field, which was "Quality"
|
||||
* in earlier versions of the library, is assumed to be a publication
|
||||
* version if it is an integer, otherwise it is ignored.
|
||||
*
|
||||
* @returns Count of selections added on success and -1 on error.
|
||||
*
|
||||
* \ref MessageOnError - this function logs a message on error
|
||||
***************************************************************************/
|
||||
int
|
||||
ms3_readselectionsfile (MS3Selections **ppselections, const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
nstime_t starttime;
|
||||
nstime_t endtime;
|
||||
uint8_t pubversion;
|
||||
char selectline[200];
|
||||
char *line;
|
||||
char *fields[MAX_SELECTION_FIELDS];
|
||||
char *cp;
|
||||
char next;
|
||||
int selectcount = 0;
|
||||
int linecount = 0;
|
||||
int fieldidx;
|
||||
uint8_t isstart2;
|
||||
uint8_t isend3;
|
||||
uint8_t isstart6;
|
||||
uint8_t isend7;
|
||||
|
||||
if (!ppselections || !filename)
|
||||
{
|
||||
ms_log (2, "Required argument not defined: 'ppselections' or 'filename'\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp (filename, "-"))
|
||||
{
|
||||
if (!(fp = fopen (filename, "rb")))
|
||||
{
|
||||
ms_log (2, "Cannot open file %s: %s\n", filename, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use stdin as special case */
|
||||
fp = stdin;
|
||||
}
|
||||
|
||||
while (fgets (selectline, sizeof (selectline) - 1, fp))
|
||||
{
|
||||
linecount++;
|
||||
|
||||
/* Reset fields array */
|
||||
for (fieldidx = 0; fieldidx < MAX_SELECTION_FIELDS; fieldidx++)
|
||||
fields[fieldidx] = NULL;
|
||||
|
||||
/* Guarantee termination */
|
||||
selectline[sizeof (selectline) - 1] = '\0';
|
||||
|
||||
line = selectline;
|
||||
|
||||
/* Trim trailing whitespace (including newlines, carriage returns, etc.) if any */
|
||||
cp = line;
|
||||
while (*cp != '\0')
|
||||
{
|
||||
cp++;
|
||||
}
|
||||
cp--;
|
||||
while (cp >= line && isspace((int)(*cp)))
|
||||
{
|
||||
*cp = '\0';
|
||||
cp--;
|
||||
}
|
||||
|
||||
/* Trim leading whitespace if any */
|
||||
cp = line;
|
||||
while (isspace((int)(*cp)))
|
||||
{
|
||||
line = cp = cp+1;
|
||||
}
|
||||
|
||||
/* Skip empty lines */
|
||||
if (!strlen (line))
|
||||
continue;
|
||||
|
||||
/* Skip comment lines */
|
||||
if (*line == '#')
|
||||
continue;
|
||||
|
||||
/* Set fields array to whitespace delimited fields */
|
||||
cp = line;
|
||||
next = 0; /* For this loop: 0 = whitespace, 1 = non-whitespace */
|
||||
fieldidx = 0;
|
||||
while (*cp && fieldidx < MAX_SELECTION_FIELDS)
|
||||
{
|
||||
if (!isspace ((int)(*cp)))
|
||||
{
|
||||
/* Field starts at transition from whitespace to non-whitespace */
|
||||
if (next == 0)
|
||||
{
|
||||
fields[fieldidx] = cp;
|
||||
fieldidx++;
|
||||
}
|
||||
|
||||
next = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Field ends at transition from non-whitespace to whitespace */
|
||||
if (next == 1)
|
||||
*cp = '\0';
|
||||
|
||||
next = 0;
|
||||
}
|
||||
|
||||
cp++;
|
||||
}
|
||||
|
||||
/* Globbing pattern to match the beginning of a date "YYYY[-/,]#..." */
|
||||
#define INITDATEGLOB "[0-9][0-9][0-9][0-9][-/,][0-9]*"
|
||||
|
||||
isstart2 = (fields[1]) ? ms_globmatch (fields[1], INITDATEGLOB) : 0;
|
||||
isend3 = (fields[2]) ? ms_globmatch (fields[2], INITDATEGLOB) : 0;
|
||||
isstart6 = (fields[5]) ? ms_globmatch (fields[5], INITDATEGLOB) : 0;
|
||||
isend7 = (fields[6]) ? ms_globmatch (fields[6], INITDATEGLOB) : 0;
|
||||
|
||||
/* Convert starttime to nstime_t */
|
||||
starttime = NSTUNSET;
|
||||
cp = NULL;
|
||||
if (isstart2)
|
||||
cp = fields[1];
|
||||
else if (isstart6)
|
||||
cp = fields[5];
|
||||
if (cp)
|
||||
{
|
||||
starttime = ms_timestr2nstime (cp);
|
||||
if (starttime == NSTUNSET)
|
||||
{
|
||||
ms_log (2, "Cannot convert data selection start time (line %d): %s\n", linecount, cp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert endtime to nstime_t */
|
||||
endtime = NSTUNSET;
|
||||
cp = NULL;
|
||||
if (isend3)
|
||||
cp = fields[2];
|
||||
else if (isend7)
|
||||
cp = fields[6];
|
||||
if (cp)
|
||||
{
|
||||
endtime = ms_timestr2nstime (cp);
|
||||
if (endtime == NSTUNSET)
|
||||
{
|
||||
ms_log (2, "Cannot convert data selection end time (line %d): %s\n", linecount, cp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Test for "SourceID [Starttime [Endtime [Pubversion]]]" */
|
||||
if (fieldidx == 1 ||
|
||||
(fieldidx == 2 && isstart2) ||
|
||||
(fieldidx == 3 && isstart2 && isend3) ||
|
||||
(fieldidx == 4 && isstart2 && isend3 && ms_isinteger(fields[3])))
|
||||
{
|
||||
/* Convert publication version to integer */
|
||||
pubversion = 0;
|
||||
if (fields[3])
|
||||
{
|
||||
long int longpver;
|
||||
|
||||
longpver = strtol (fields[3], NULL, 10);
|
||||
|
||||
if (longpver < 0 || longpver > 255 )
|
||||
{
|
||||
ms_log (2, "Cannot convert publication version (line %d): %s\n", linecount, fields[3]);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pubversion = (uint8_t) longpver;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add selection to list */
|
||||
if (ms3_addselect (ppselections, fields[0], starttime, endtime, pubversion))
|
||||
{
|
||||
ms_log (2, "%s: Error adding selection on line %d\n", filename, linecount);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Test for "Network Station Location Channel [Quality [Starttime [Endtime]]]" */
|
||||
else if (fieldidx == 4 || fieldidx == 5 ||
|
||||
(fieldidx == 6 && isstart6) ||
|
||||
(fieldidx == 7 && isstart6 && isend7))
|
||||
{
|
||||
/* Convert quality field to publication version if integer */
|
||||
pubversion = 0;
|
||||
if (fields[4] && ms_isinteger(fields[4]))
|
||||
{
|
||||
long int longpver;
|
||||
|
||||
longpver = strtol (fields[4], NULL, 10);
|
||||
|
||||
if (longpver < 0 || longpver > 255 )
|
||||
{
|
||||
ms_log (2, "Cannot convert publication version (line %d): %s\n", linecount, fields[4]);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pubversion = (uint8_t) longpver;
|
||||
}
|
||||
}
|
||||
|
||||
if (ms3_addselect_comp (ppselections, fields[0], fields[1], fields[2], fields[3],
|
||||
starttime, endtime, pubversion))
|
||||
{
|
||||
ms_log (2, "%s: Error adding selection on line %d\n", filename, linecount);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ms_log (1, "%s: Skipping unrecognized data selection on line %d\n", filename, linecount);
|
||||
}
|
||||
|
||||
selectcount++;
|
||||
}
|
||||
|
||||
if (fp != stdin)
|
||||
fclose (fp);
|
||||
|
||||
return selectcount;
|
||||
} /* End of ms_readselectionsfile() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Free all memory associated with a ::MS3Selections
|
||||
*
|
||||
* All memory from one or more ::MS3Selections (in a linked list) are freed.
|
||||
*
|
||||
* @param[in] selections Start of ::MS3Selections to free
|
||||
***************************************************************************/
|
||||
void
|
||||
ms3_freeselections (MS3Selections *selections)
|
||||
{
|
||||
MS3Selections *select;
|
||||
MS3Selections *selectnext;
|
||||
MS3SelectTime *selecttime;
|
||||
MS3SelectTime *selecttimenext;
|
||||
|
||||
if (selections)
|
||||
{
|
||||
select = selections;
|
||||
|
||||
while (select)
|
||||
{
|
||||
selectnext = select->next;
|
||||
|
||||
selecttime = select->timewindows;
|
||||
|
||||
while (selecttime)
|
||||
{
|
||||
selecttimenext = selecttime->next;
|
||||
|
||||
libmseed_memory.free (selecttime);
|
||||
|
||||
selecttime = selecttimenext;
|
||||
}
|
||||
|
||||
libmseed_memory.free (select);
|
||||
|
||||
select = selectnext;
|
||||
}
|
||||
}
|
||||
|
||||
} /* End of ms3_freeselections() */
|
||||
|
||||
/**********************************************************************/ /**
|
||||
* @brief Print the selections list using the ms_log() facility.
|
||||
*
|
||||
* All selections are printed with simple formatting.
|
||||
*
|
||||
* @param[in] selections Start of ::MS3Selections to print
|
||||
***************************************************************************/
|
||||
void
|
||||
ms3_printselections (const MS3Selections *selections)
|
||||
{
|
||||
const MS3Selections *select;
|
||||
MS3SelectTime *selecttime;
|
||||
char starttime[50];
|
||||
char endtime[50];
|
||||
|
||||
if (!selections)
|
||||
return;
|
||||
|
||||
select = selections;
|
||||
while (select)
|
||||
{
|
||||
ms_log (0, "Selection: %s pubversion: %d\n",
|
||||
select->sidpattern, select->pubversion);
|
||||
|
||||
selecttime = select->timewindows;
|
||||
while (selecttime)
|
||||
{
|
||||
if (selecttime->starttime != NSTERROR && selecttime->starttime != NSTUNSET)
|
||||
ms_nstime2timestr (selecttime->starttime, starttime, ISOMONTHDAY_Z, NANO_MICRO_NONE);
|
||||
else
|
||||
strncpy (starttime, "No start time", sizeof (starttime) - 1);
|
||||
|
||||
if (selecttime->endtime != NSTERROR && selecttime->endtime != NSTUNSET)
|
||||
ms_nstime2timestr (selecttime->endtime, endtime, ISOMONTHDAY_Z, NANO_MICRO_NONE);
|
||||
else
|
||||
strncpy (endtime, "No end time", sizeof (endtime) - 1);
|
||||
|
||||
ms_log (0, " %30s %30s\n", starttime, endtime);
|
||||
|
||||
selecttime = selecttime->next;
|
||||
}
|
||||
|
||||
select = select->next;
|
||||
}
|
||||
} /* End of ms3_printselections() */
|
||||
|
||||
/***************************************************************************
|
||||
* ms_isinteger:
|
||||
*
|
||||
* Test a string for all digits, i.e. and integer
|
||||
*
|
||||
* Returns 1 if is integer and 0 otherwise.
|
||||
***************************************************************************/
|
||||
static int
|
||||
ms_isinteger (const char *string)
|
||||
{
|
||||
while (*string)
|
||||
{
|
||||
if (!isdigit((int)(*string)))
|
||||
return 0;
|
||||
string++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* robust glob pattern matcher
|
||||
* ozan s. yigit/dec 1994
|
||||
* public domain
|
||||
*
|
||||
* glob patterns:
|
||||
* * matches zero or more characters
|
||||
* ? matches any single character
|
||||
* [set] matches any character in the set
|
||||
* [^set] matches any character NOT in the set
|
||||
* where a set is a group of characters or ranges. a range
|
||||
* is written as two characters seperated with a hyphen: a-z denotes
|
||||
* all characters between a to z inclusive.
|
||||
* [-set] set matches a literal hypen and any character in the set
|
||||
* []set] matches a literal close bracket and any character in the set
|
||||
*
|
||||
* char matches itself except where char is '*' or '?' or '['
|
||||
* \char matches char, including any pattern character
|
||||
*
|
||||
* examples:
|
||||
* a*c ac abc abbc ...
|
||||
* a?c acc abc aXc ...
|
||||
* a[a-z]c aac abc acc ...
|
||||
* a[-a-z]c a-c aac abc ...
|
||||
*
|
||||
* Revision 1.4 2004/12/26 12:38:00 ct
|
||||
* Changed function name (amatch -> globmatch), variables and
|
||||
* formatting for clarity. Also add matching header globmatch.h.
|
||||
*
|
||||
* Revision 1.3 1995/09/14 23:24:23 oz
|
||||
* removed boring test/main code.
|
||||
*
|
||||
* Revision 1.2 94/12/11 10:38:15 oz
|
||||
* charset code fixed. it is now robust and interprets all
|
||||
* variations of charset [i think] correctly, including [z-a] etc.
|
||||
*
|
||||
* Revision 1.1 94/12/08 12:45:23 oz
|
||||
* Initial revision
|
||||
***********************************************************************/
|
||||
|
||||
#define GLOBMATCH_TRUE 1
|
||||
#define GLOBMATCH_FALSE 0
|
||||
#define GLOBMATCH_NEGATE '^' /* std char set negation char */
|
||||
|
||||
/***********************************************************************
|
||||
* ms_globmatch:
|
||||
*
|
||||
* Check if a string matches a globbing pattern.
|
||||
*
|
||||
* Return 0 if string does not match pattern and non-zero otherwise.
|
||||
**********************************************************************/
|
||||
static int
|
||||
ms_globmatch (const char *string, const char *pattern)
|
||||
{
|
||||
int negate;
|
||||
int match;
|
||||
int c;
|
||||
|
||||
while (*pattern)
|
||||
{
|
||||
if (!*string && *pattern != '*')
|
||||
return GLOBMATCH_FALSE;
|
||||
|
||||
switch (c = *pattern++)
|
||||
{
|
||||
|
||||
case '*':
|
||||
while (*pattern == '*')
|
||||
pattern++;
|
||||
|
||||
if (!*pattern)
|
||||
return GLOBMATCH_TRUE;
|
||||
|
||||
if (*pattern != '?' && *pattern != '[' && *pattern != '\\')
|
||||
while (*string && *pattern != *string)
|
||||
string++;
|
||||
|
||||
while (*string)
|
||||
{
|
||||
if (ms_globmatch (string, pattern))
|
||||
return GLOBMATCH_TRUE;
|
||||
string++;
|
||||
}
|
||||
return GLOBMATCH_FALSE;
|
||||
|
||||
case '?':
|
||||
if (*string)
|
||||
break;
|
||||
return GLOBMATCH_FALSE;
|
||||
|
||||
/* set specification is inclusive, that is [a-z] is a, z and
|
||||
* everything in between. this means [z-a] may be interpreted
|
||||
* as a set that contains z, a and nothing in between.
|
||||
*/
|
||||
case '[':
|
||||
if (*pattern != GLOBMATCH_NEGATE)
|
||||
negate = GLOBMATCH_FALSE;
|
||||
else
|
||||
{
|
||||
negate = GLOBMATCH_TRUE;
|
||||
pattern++;
|
||||
}
|
||||
|
||||
match = GLOBMATCH_FALSE;
|
||||
|
||||
while (!match && (c = *pattern++))
|
||||
{
|
||||
if (!*pattern)
|
||||
return GLOBMATCH_FALSE;
|
||||
|
||||
if (*pattern == '-') /* c-c */
|
||||
{
|
||||
if (!*++pattern)
|
||||
return GLOBMATCH_FALSE;
|
||||
if (*pattern != ']')
|
||||
{
|
||||
if (*string == c || *string == *pattern ||
|
||||
(*string > c && *string < *pattern))
|
||||
match = GLOBMATCH_TRUE;
|
||||
}
|
||||
else
|
||||
{ /* c-] */
|
||||
if (*string >= c)
|
||||
match = GLOBMATCH_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* cc or c] */
|
||||
{
|
||||
if (c == *string)
|
||||
match = GLOBMATCH_TRUE;
|
||||
if (*pattern != ']')
|
||||
{
|
||||
if (*pattern == *string)
|
||||
match = GLOBMATCH_TRUE;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (negate == match)
|
||||
return GLOBMATCH_FALSE;
|
||||
|
||||
/* If there is a match, skip past the charset and continue on */
|
||||
while (*pattern && *pattern != ']')
|
||||
pattern++;
|
||||
if (!*pattern++) /* oops! */
|
||||
return GLOBMATCH_FALSE;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if (*pattern)
|
||||
c = *pattern++;
|
||||
default:
|
||||
if (c != *string)
|
||||
return GLOBMATCH_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
string++;
|
||||
}
|
||||
|
||||
return !*string;
|
||||
} /* End of ms_globmatch() */
|
@ -0,0 +1,49 @@
|
||||
# This Makefile requires GNU make, sometimes available as gmake.
|
||||
#
|
||||
# A simple test suite for libmseed.
|
||||
# See README for description.
|
||||
#
|
||||
# Build environment can be configured the following
|
||||
# environment variables:
|
||||
# CC : Specify the C compiler to use
|
||||
# CFLAGS : Specify compiler options to use
|
||||
|
||||
# Required compiler parameters
|
||||
CFLAGS += -I.. -I.
|
||||
|
||||
LDFLAGS += -L..
|
||||
LDLIBS := -lmseed $(LDLIBS)
|
||||
|
||||
# Source code from example programs
|
||||
EXAMPLE_SRCS := $(sort $(wildcard lm_*.c))
|
||||
EXAMPLE_BINS := $(EXAMPLE_SRCS:%.c=%)
|
||||
|
||||
# Source code for tests
|
||||
TEST_SRCS := $(sort $(wildcard test-*.c))
|
||||
TEST_RUNNER := test-runner
|
||||
|
||||
# ASCII color coding for test results, green for PASSED and red for FAILED
|
||||
PASSED := \033[0;32mPASSED\033[0m
|
||||
FAILED := \033[0;31mFAILED\033[0m
|
||||
|
||||
test all: $(EXAMPLE_BINS) $(TEST_RUNNER) runtests
|
||||
|
||||
# Build example programs and check for executables
|
||||
$(EXAMPLE_BINS) : % : %.c
|
||||
@$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS); exit 0;
|
||||
@if test -x $@; \
|
||||
then printf '$(PASSED) Building $<\n'; \
|
||||
else printf '$(FAILED) Building $<\n'; exit 1; \
|
||||
fi
|
||||
|
||||
# Build tests
|
||||
.PHONY: $(TEST_RUNNER)
|
||||
$(TEST_RUNNER):
|
||||
$(CC) $(CFLAGS) -o $@ $(TEST_SRCS) $(LDFLAGS) $(LDLIBS) -Wno-unused-but-set-variable
|
||||
|
||||
# Execute tests
|
||||
runtests: $(TEST_RUNNER)
|
||||
@./$(TEST_RUNNER)
|
||||
|
||||
clean:
|
||||
@rm -rf $(EXAMPLE_BINS) $(TEST_RUNNER) testdata-* *.dSYM
|
@ -0,0 +1,22 @@
|
||||
#
|
||||
# Nmake file for libmseed tests - MS Visual C/C++
|
||||
# Use 'nmake -f Makefile.win'
|
||||
|
||||
INCS = /I. /I..
|
||||
LIBS = ..\libmseed.lib
|
||||
OPTS = /D_CRT_SECURE_NO_WARNINGS
|
||||
|
||||
TEST_RUNNER = test-runner.exe
|
||||
|
||||
test: $(TEST_RUNNER)
|
||||
$(TEST_RUNNER)
|
||||
|
||||
$(TEST_RUNNER): test-*.obj
|
||||
link $** $(LIBS) /nologo /OUT:$@
|
||||
|
||||
.c.obj:
|
||||
$(CC) $(CFLAGS) $(INCS) $(OPTS) /nologo /c $<
|
||||
|
||||
# Clean-up directives
|
||||
clean:
|
||||
-del a.out core *.o *.obj *% *~ $(TEST_RUNNER) testdata-*
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue