We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
GCF read fails on windows (recent python + numpy 1.22)
https://tests.obspy.org/115141/ & https://tests.obspy.org/115136/ on two independent machines show the error

I suspect it's numpy-dtype related:

```
Traceback (most recent call last):
File "C:\Miniconda3\envs\test\lib\site-packages\numpy\core\fromnumeric.py", line 57, in _wrapfunc
return bound(*args, **kwds)
TypeError: the resolved dtypes are not compatible with add.accumulate. Resolved (dtype('int32'), dtype('int32'), dtype('int32'))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:\a\obspy\obspy\obspy\io\gcf\tests\test_core.py", line 72, in test_read_via_module
st = _read_gcf(filename)
File "D:\a\obspy\obspy\obspy\io\gcf\core.py", line 89, in _read_gcf
hd = libgcf.read(f, **kwargs)
File "D:\a\obspy\obspy\obspy\io\gcf\libgcf.py", line 167, in read
return read_data_block(f, headonly=False, **kwargs)
File "D:\a\obspy\obspy\obspy\io\gcf\libgcf.py", line 144, in read_data_block
data = (fic + np.cumsum(data)).astype('i4')
File "<__array_function__ internals>", line 180, in cumsum
File "C:\Miniconda3\envs\test\lib\site-packages\numpy\core\fromnumeric.py", line 2569, in cumsum
return _wrapfunc(a, 'cumsum', axis=axis, dtype=dtype, out=out)
File "C:\Miniconda3\envs\test\lib\site-packages\numpy\core\fromnumeric.py", line 66, in _wrapfunc
return _wrapit(obj, method, *args, **kwds)
File "C:\Miniconda3\envs\test\lib\site-packages\numpy\core\fromnumeric.py", line 43, in _wrapit
result = getattr(asarray(obj), method)(*args, **kwds)
TypeError: the resolved dtypes are not compatible with add.accumulate. Resolved (dtype('int32'), dtype('int32'), dtype('int32'))
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `obspy/io/gcf/libgcf.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # reads Guralp Compressed Format (GCF) Files
3 # By Ran Novitsky Nof @ BSL, 2016
4 # ran.nof@gmail.com
5 # Based on Guralp's GCF reference (GCF-RFC-GCFR, Issue C, 2011-01-05)
6 # more details available from: http://www.guralp.com/apps/ok?doc=GCF_Intro
7 # last access: June, 2016
8 import numpy as np
9 
10 from obspy import UTCDateTime
11 
12 SPS_D = {  # Table 3.1: special sample rates
13     157: 0.1,
14     161: 0.125,
15     162: 0.2,
16     164: 0.25,
17     167: 0.5,
18     171: 400,
19     174: 500,
20     176: 1000,
21     179: 2000,
22     181: 4000}
23 TIME_OFFSETS_D = {  # Table 3.1: Time fractional offset denominator
24     171: 8.,
25     174: 2.,
26     176: 4.,
27     179: 8.,
28     181: 16.}
29 COMPRESSION_D = {  # Table 3.2: format field to data type
30     1: '>i4',
31     2: '>i2',
32     4: '>i1'}
33 
34 
35 def is_gcf(f):
36     """
37     Test if file is GCF by reading at least 1 data block
38     """
39     header, data = read_data_block(f)
40 
41 
42 def decode36(data):
43     """
44     Converts an integer into a base36 string.
45     """
46     # http://geophysics.eas.gatech.edu/GTEQ/Scream4.4/Decoding_Base_36_numbers_C.htm
47     s = ''
48     while data:
49         imed = data % 36
50         if imed > 9:
51             pos = imed - 10 + ord('A')
52         else:
53             pos = imed + ord('0')
54         c = chr(pos)
55         s = c + s
56         data = data // 36
57     return s
58 
59 
60 def decode_date_time(data):
61     """
62     Decode date and time field.
63 
64     The date code is a 32 bit value specifying the start time of the block.
65     Bits 0-16 contain the number of seconds since midnight,
66     and bits 17-31 the number of days since 17th November 1989.
67     """
68     # prevent numpy array
69     days = int(data >> 17)
70     secs = int(data & 0x1FFFF)
71     starttime = UTCDateTime('1989-11-17') + days * 86400 + secs
72     return starttime
73 
74 
75 def read_data_block(f, headonly=False, channel_prefix="HH", **kwargs):
76     """
77     Read one data block from GCF file.
78 
79     more details can be found here:
80     http://geophysics.eas.gatech.edu/GTEQ/Scream4.4/GCF_Specification.htm
81     f - file object to read from
82     if skipData is True, Only header is returned.
83     if not a data block (SPS=0) - returns None.
84     """
85     # get ID
86     sysid = f.read(4)
87     if not sysid:
88         raise EOFError  # got to EOF
89     sysid = np.frombuffer(sysid, count=1, dtype='>u4')
90     if sysid >> 31 & 0b1 > 0:
91         sysid = (sysid << 6) >> 6
92     if isinstance(sysid, np.ndarray) and sysid.shape == (1,):
93         sysid = sysid[0]
94     else:
95         raise ValueError('sysid should be a single element np.ndarray')
96     sysid = decode36(sysid)
97     # get Stream ID
98     stid = np.frombuffer(f.read(4), count=1, dtype='>u4')
99     if isinstance(stid, np.ndarray) and stid.shape == (1,):
100         stid = stid[0]
101     else:
102         raise ValueError('stid should be a single element np.ndarray')
103     stid = decode36(stid)
104     # get Date & Time
105     data = np.frombuffer(f.read(4), count=1, dtype='>u4')
106     starttime = decode_date_time(data)
107     # get data format
108     # get reserved, SPS, data type compression,
109     # number of 32bit records (num_records)
110     reserved, sps, compress, num_records = np.frombuffer(f.read(4), count=4,
111                                                          dtype='>u1')
112     compression = compress & 0b00000111  # get compression code
113     t_offset = compress >> 4  # get time offset
114     if t_offset > 0:
115         starttime = starttime + t_offset / TIME_OFFSETS_D[sps]
116     if sps in SPS_D:
117         sps = SPS_D[sps]  # get special SPS value if needed
118     if not sps:
119         f.seek(num_records * 4, 1)  # skip if not a data block
120         if 1008 - num_records * 4 > 0:
121             # keep skipping to get 1008 record
122             f.seek(1008 - num_records * 4, 1)
123         return None
124     npts = num_records * compression  # number of samples
125     header = {}
126     header['starttime'] = starttime
127     header['station'] = stid[:-2]
128     header['channel'] = (channel_prefix[:2] + stid[-2]).upper()
129     header['sampling_rate'] = float(sps)
130     header['npts'] = npts
131     if headonly:
132         f.seek(4 * (num_records + 2), 1)  # skip data part (inc. FIC and RIC)
133         # skip to end of block if only partly filled with data
134         if 1000 - num_records * 4 > 0:
135             f.seek(1000 - num_records * 4, 1)
136         return header
137     else:
138         # get FIC
139         fic = np.frombuffer(f.read(4), count=1, dtype='>i4')
140         # get incremental data
141         data = np.frombuffer(f.read(4 * num_records), count=npts,
142                              dtype=COMPRESSION_D[compression])
143         # construct time series
144         data = (fic + np.cumsum(data)).astype('i4')
145         # get RIC
146         ric = np.frombuffer(f.read(4), count=1, dtype='>i4')
147         # skip to end of block if only partly filled with data
148         if 1000 - num_records * 4 > 0:
149             f.seek(1000 - num_records * 4, 1)
150         # verify last data sample matches RIC
151         if not data[-1] == ric:
152             raise ValueError("Last sample mismatch with RIC")
153         return header, data
154 
155 
156 def read_header(f, **kwargs):
157     """
158     Reads header only from GCF file.
159     """
160     return read_data_block(f, headonly=True, **kwargs)
161 
162 
163 def read(f, **kwargs):
164     """
165     Reads header and data from GCF file.
166     """
167     return read_data_block(f, headonly=False, **kwargs)
168
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/obspy/io/gcf/libgcf.py b/obspy/io/gcf/libgcf.py
--- a/obspy/io/gcf/libgcf.py
+++ b/obspy/io/gcf/libgcf.py
@@ -5,6 +5,8 @@
 # Based on Guralp's GCF reference (GCF-RFC-GCFR, Issue C, 2011-01-05)
 # more details available from: http://www.guralp.com/apps/ok?doc=GCF_Intro
 # last access: June, 2016
+import struct
+
 import numpy as np
 
 from obspy import UTCDateTime
@@ -27,9 +29,10 @@
     179: 8.,
     181: 16.}
 COMPRESSION_D = {  # Table 3.2: format field to data type
-    1: '>i4',
-    2: '>i2',
-    4: '>i1'}
+    1: 'i',  # 4 bytes
+    2: 'h',  # 2 bytes
+    4: 'b',  # 1 byte
+}
 
 
 def is_gcf(f):
@@ -86,29 +89,20 @@
     sysid = f.read(4)
     if not sysid:
         raise EOFError  # got to EOF
-    sysid = np.frombuffer(sysid, count=1, dtype='>u4')
+    sysid, = struct.unpack('>I', sysid)
     if sysid >> 31 & 0b1 > 0:
         sysid = (sysid << 6) >> 6
-    if isinstance(sysid, np.ndarray) and sysid.shape == (1,):
-        sysid = sysid[0]
-    else:
-        raise ValueError('sysid should be a single element np.ndarray')
     sysid = decode36(sysid)
     # get Stream ID
-    stid = np.frombuffer(f.read(4), count=1, dtype='>u4')
-    if isinstance(stid, np.ndarray) and stid.shape == (1,):
-        stid = stid[0]
-    else:
-        raise ValueError('stid should be a single element np.ndarray')
+    stid, = struct.unpack('>I', f.read(4))
     stid = decode36(stid)
     # get Date & Time
-    data = np.frombuffer(f.read(4), count=1, dtype='>u4')
+    data, = struct.unpack('>I', f.read(4))
     starttime = decode_date_time(data)
     # get data format
     # get reserved, SPS, data type compression,
     # number of 32bit records (num_records)
-    reserved, sps, compress, num_records = np.frombuffer(f.read(4), count=4,
-                                                         dtype='>u1')
+    reserved, sps, compress, num_records = struct.unpack('>4B', f.read(4))
     compression = compress & 0b00000111  # get compression code
     t_offset = compress >> 4  # get time offset
     if t_offset > 0:
@@ -136,14 +130,14 @@
         return header
     else:
         # get FIC
-        fic = np.frombuffer(f.read(4), count=1, dtype='>i4')
+        fic, = struct.unpack('>i', f.read(4))
         # get incremental data
-        data = np.frombuffer(f.read(4 * num_records), count=npts,
-                             dtype=COMPRESSION_D[compression])
+        data = struct.unpack(f'>{npts}{COMPRESSION_D[compression]}',
+                             f.read(4 * num_records))
         # construct time series
         data = (fic + np.cumsum(data)).astype('i4')
         # get RIC
-        ric = np.frombuffer(f.read(4), count=1, dtype='>i4')
+        ric, = struct.unpack('>i', f.read(4))
         # skip to end of block if only partly filled with data
         if 1000 - num_records * 4 > 0:
             f.seek(1000 - num_records * 4, 1)

{"golden_diff": "diff --git a/obspy/io/gcf/libgcf.py b/obspy/io/gcf/libgcf.py\n--- a/obspy/io/gcf/libgcf.py\n+++ b/obspy/io/gcf/libgcf.py\n@@ -5,6 +5,8 @@\n # Based on Guralp's GCF reference (GCF-RFC-GCFR, Issue C, 2011-01-05)\n # more details available from: http://www.guralp.com/apps/ok?doc=GCF_Intro\n # last access: June, 2016\n+import struct\n+\n import numpy as np\n \n from obspy import UTCDateTime\n@@ -27,9 +29,10 @@\n     179: 8.,\n     181: 16.}\n COMPRESSION_D = {  # Table 3.2: format field to data type\n-    1: '>i4',\n-    2: '>i2',\n-    4: '>i1'}\n+    1: 'i',  # 4 bytes\n+    2: 'h',  # 2 bytes\n+    4: 'b',  # 1 byte\n+}\n \n \n def is_gcf(f):\n@@ -86,29 +89,20 @@\n     sysid = f.read(4)\n     if not sysid:\n         raise EOFError  # got to EOF\n-    sysid = np.frombuffer(sysid, count=1, dtype='>u4')\n+    sysid, = struct.unpack('>I', sysid)\n     if sysid >> 31 & 0b1 > 0:\n         sysid = (sysid << 6) >> 6\n-    if isinstance(sysid, np.ndarray) and sysid.shape == (1,):\n-        sysid = sysid[0]\n-    else:\n-        raise ValueError('sysid should be a single element np.ndarray')\n     sysid = decode36(sysid)\n     # get Stream ID\n-    stid = np.frombuffer(f.read(4), count=1, dtype='>u4')\n-    if isinstance(stid, np.ndarray) and stid.shape == (1,):\n-        stid = stid[0]\n-    else:\n-        raise ValueError('stid should be a single element np.ndarray')\n+    stid, = struct.unpack('>I', f.read(4))\n     stid = decode36(stid)\n     # get Date & Time\n-    data = np.frombuffer(f.read(4), count=1, dtype='>u4')\n+    data, = struct.unpack('>I', f.read(4))\n     starttime = decode_date_time(data)\n     # get data format\n     # get reserved, SPS, data type compression,\n     # number of 32bit records (num_records)\n-    reserved, sps, compress, num_records = np.frombuffer(f.read(4), count=4,\n-                                                         dtype='>u1')\n+    reserved, sps, compress, num_records = struct.unpack('>4B', f.read(4))\n     compression = compress & 0b00000111  # get compression code\n     t_offset = compress >> 4  # get time offset\n     if t_offset > 0:\n@@ -136,14 +130,14 @@\n         return header\n     else:\n         # get FIC\n-        fic = np.frombuffer(f.read(4), count=1, dtype='>i4')\n+        fic, = struct.unpack('>i', f.read(4))\n         # get incremental data\n-        data = np.frombuffer(f.read(4 * num_records), count=npts,\n-                             dtype=COMPRESSION_D[compression])\n+        data = struct.unpack(f'>{npts}{COMPRESSION_D[compression]}',\n+                             f.read(4 * num_records))\n         # construct time series\n         data = (fic + np.cumsum(data)).astype('i4')\n         # get RIC\n-        ric = np.frombuffer(f.read(4), count=1, dtype='>i4')\n+        ric, = struct.unpack('>i', f.read(4))\n         # skip to end of block if only partly filled with data\n         if 1000 - num_records * 4 > 0:\n             f.seek(1000 - num_records * 4, 1)\n", "issue": "GCF read fails on windows (recent python + numpy 1.22)\nhttps://tests.obspy.org/115141/ & https://tests.obspy.org/115136/ on two independent machines show the error\r\n\r\nI suspect it's numpy-dtype related:\r\n\r\n```\r\nTraceback (most recent call last):\r\nFile \"C:\\Miniconda3\\envs\\test\\lib\\site-packages\\numpy\\core\\fromnumeric.py\", line 57, in _wrapfunc\r\nreturn bound(*args, **kwds)\r\nTypeError: the resolved dtypes are not compatible with add.accumulate. Resolved (dtype('int32'), dtype('int32'), dtype('int32'))\r\nDuring handling of the above exception, another exception occurred:\r\nTraceback (most recent call last):\r\nFile \"D:\\a\\obspy\\obspy\\obspy\\io\\gcf\\tests\\test_core.py\", line 72, in test_read_via_module\r\nst = _read_gcf(filename)\r\nFile \"D:\\a\\obspy\\obspy\\obspy\\io\\gcf\\core.py\", line 89, in _read_gcf\r\nhd = libgcf.read(f, **kwargs)\r\nFile \"D:\\a\\obspy\\obspy\\obspy\\io\\gcf\\libgcf.py\", line 167, in read\r\nreturn read_data_block(f, headonly=False, **kwargs)\r\nFile \"D:\\a\\obspy\\obspy\\obspy\\io\\gcf\\libgcf.py\", line 144, in read_data_block\r\ndata = (fic + np.cumsum(data)).astype('i4')\r\nFile \"<__array_function__ internals>\", line 180, in cumsum\r\nFile \"C:\\Miniconda3\\envs\\test\\lib\\site-packages\\numpy\\core\\fromnumeric.py\", line 2569, in cumsum\r\nreturn _wrapfunc(a, 'cumsum', axis=axis, dtype=dtype, out=out)\r\nFile \"C:\\Miniconda3\\envs\\test\\lib\\site-packages\\numpy\\core\\fromnumeric.py\", line 66, in _wrapfunc\r\nreturn _wrapit(obj, method, *args, **kwds)\r\nFile \"C:\\Miniconda3\\envs\\test\\lib\\site-packages\\numpy\\core\\fromnumeric.py\", line 43, in _wrapit\r\nresult = getattr(asarray(obj), method)(*args, **kwds)\r\nTypeError: the resolved dtypes are not compatible with add.accumulate. Resolved (dtype('int32'), dtype('int32'), dtype('int32'))\r\n```\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# reads Guralp Compressed Format (GCF) Files\n# By Ran Novitsky Nof @ BSL, 2016\n# ran.nof@gmail.com\n# Based on Guralp's GCF reference (GCF-RFC-GCFR, Issue C, 2011-01-05)\n# more details available from: http://www.guralp.com/apps/ok?doc=GCF_Intro\n# last access: June, 2016\nimport numpy as np\n\nfrom obspy import UTCDateTime\n\nSPS_D = {  # Table 3.1: special sample rates\n    157: 0.1,\n    161: 0.125,\n    162: 0.2,\n    164: 0.25,\n    167: 0.5,\n    171: 400,\n    174: 500,\n    176: 1000,\n    179: 2000,\n    181: 4000}\nTIME_OFFSETS_D = {  # Table 3.1: Time fractional offset denominator\n    171: 8.,\n    174: 2.,\n    176: 4.,\n    179: 8.,\n    181: 16.}\nCOMPRESSION_D = {  # Table 3.2: format field to data type\n    1: '>i4',\n    2: '>i2',\n    4: '>i1'}\n\n\ndef is_gcf(f):\n    \"\"\"\n    Test if file is GCF by reading at least 1 data block\n    \"\"\"\n    header, data = read_data_block(f)\n\n\ndef decode36(data):\n    \"\"\"\n    Converts an integer into a base36 string.\n    \"\"\"\n    # http://geophysics.eas.gatech.edu/GTEQ/Scream4.4/Decoding_Base_36_numbers_C.htm\n    s = ''\n    while data:\n        imed = data % 36\n        if imed > 9:\n            pos = imed - 10 + ord('A')\n        else:\n            pos = imed + ord('0')\n        c = chr(pos)\n        s = c + s\n        data = data // 36\n    return s\n\n\ndef decode_date_time(data):\n    \"\"\"\n    Decode date and time field.\n\n    The date code is a 32 bit value specifying the start time of the block.\n    Bits 0-16 contain the number of seconds since midnight,\n    and bits 17-31 the number of days since 17th November 1989.\n    \"\"\"\n    # prevent numpy array\n    days = int(data >> 17)\n    secs = int(data & 0x1FFFF)\n    starttime = UTCDateTime('1989-11-17') + days * 86400 + secs\n    return starttime\n\n\ndef read_data_block(f, headonly=False, channel_prefix=\"HH\", **kwargs):\n    \"\"\"\n    Read one data block from GCF file.\n\n    more details can be found here:\n    http://geophysics.eas.gatech.edu/GTEQ/Scream4.4/GCF_Specification.htm\n    f - file object to read from\n    if skipData is True, Only header is returned.\n    if not a data block (SPS=0) - returns None.\n    \"\"\"\n    # get ID\n    sysid = f.read(4)\n    if not sysid:\n        raise EOFError  # got to EOF\n    sysid = np.frombuffer(sysid, count=1, dtype='>u4')\n    if sysid >> 31 & 0b1 > 0:\n        sysid = (sysid << 6) >> 6\n    if isinstance(sysid, np.ndarray) and sysid.shape == (1,):\n        sysid = sysid[0]\n    else:\n        raise ValueError('sysid should be a single element np.ndarray')\n    sysid = decode36(sysid)\n    # get Stream ID\n    stid = np.frombuffer(f.read(4), count=1, dtype='>u4')\n    if isinstance(stid, np.ndarray) and stid.shape == (1,):\n        stid = stid[0]\n    else:\n        raise ValueError('stid should be a single element np.ndarray')\n    stid = decode36(stid)\n    # get Date & Time\n    data = np.frombuffer(f.read(4), count=1, dtype='>u4')\n    starttime = decode_date_time(data)\n    # get data format\n    # get reserved, SPS, data type compression,\n    # number of 32bit records (num_records)\n    reserved, sps, compress, num_records = np.frombuffer(f.read(4), count=4,\n                                                         dtype='>u1')\n    compression = compress & 0b00000111  # get compression code\n    t_offset = compress >> 4  # get time offset\n    if t_offset > 0:\n        starttime = starttime + t_offset / TIME_OFFSETS_D[sps]\n    if sps in SPS_D:\n        sps = SPS_D[sps]  # get special SPS value if needed\n    if not sps:\n        f.seek(num_records * 4, 1)  # skip if not a data block\n        if 1008 - num_records * 4 > 0:\n            # keep skipping to get 1008 record\n            f.seek(1008 - num_records * 4, 1)\n        return None\n    npts = num_records * compression  # number of samples\n    header = {}\n    header['starttime'] = starttime\n    header['station'] = stid[:-2]\n    header['channel'] = (channel_prefix[:2] + stid[-2]).upper()\n    header['sampling_rate'] = float(sps)\n    header['npts'] = npts\n    if headonly:\n        f.seek(4 * (num_records + 2), 1)  # skip data part (inc. FIC and RIC)\n        # skip to end of block if only partly filled with data\n        if 1000 - num_records * 4 > 0:\n            f.seek(1000 - num_records * 4, 1)\n        return header\n    else:\n        # get FIC\n        fic = np.frombuffer(f.read(4), count=1, dtype='>i4')\n        # get incremental data\n        data = np.frombuffer(f.read(4 * num_records), count=npts,\n                             dtype=COMPRESSION_D[compression])\n        # construct time series\n        data = (fic + np.cumsum(data)).astype('i4')\n        # get RIC\n        ric = np.frombuffer(f.read(4), count=1, dtype='>i4')\n        # skip to end of block if only partly filled with data\n        if 1000 - num_records * 4 > 0:\n            f.seek(1000 - num_records * 4, 1)\n        # verify last data sample matches RIC\n        if not data[-1] == ric:\n            raise ValueError(\"Last sample mismatch with RIC\")\n        return header, data\n\n\ndef read_header(f, **kwargs):\n    \"\"\"\n    Reads header only from GCF file.\n    \"\"\"\n    return read_data_block(f, headonly=True, **kwargs)\n\n\ndef read(f, **kwargs):\n    \"\"\"\n    Reads header and data from GCF file.\n    \"\"\"\n    return read_data_block(f, headonly=False, **kwargs)\n", "path": "obspy/io/gcf/libgcf.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# reads Guralp Compressed Format (GCF) Files\n# By Ran Novitsky Nof @ BSL, 2016\n# ran.nof@gmail.com\n# Based on Guralp's GCF reference (GCF-RFC-GCFR, Issue C, 2011-01-05)\n# more details available from: http://www.guralp.com/apps/ok?doc=GCF_Intro\n# last access: June, 2016\nimport struct\n\nimport numpy as np\n\nfrom obspy import UTCDateTime\n\nSPS_D = {  # Table 3.1: special sample rates\n    157: 0.1,\n    161: 0.125,\n    162: 0.2,\n    164: 0.25,\n    167: 0.5,\n    171: 400,\n    174: 500,\n    176: 1000,\n    179: 2000,\n    181: 4000}\nTIME_OFFSETS_D = {  # Table 3.1: Time fractional offset denominator\n    171: 8.,\n    174: 2.,\n    176: 4.,\n    179: 8.,\n    181: 16.}\nCOMPRESSION_D = {  # Table 3.2: format field to data type\n    1: 'i',  # 4 bytes\n    2: 'h',  # 2 bytes\n    4: 'b',  # 1 byte\n}\n\n\ndef is_gcf(f):\n    \"\"\"\n    Test if file is GCF by reading at least 1 data block\n    \"\"\"\n    header, data = read_data_block(f)\n\n\ndef decode36(data):\n    \"\"\"\n    Converts an integer into a base36 string.\n    \"\"\"\n    # http://geophysics.eas.gatech.edu/GTEQ/Scream4.4/Decoding_Base_36_numbers_C.htm\n    s = ''\n    while data:\n        imed = data % 36\n        if imed > 9:\n            pos = imed - 10 + ord('A')\n        else:\n            pos = imed + ord('0')\n        c = chr(pos)\n        s = c + s\n        data = data // 36\n    return s\n\n\ndef decode_date_time(data):\n    \"\"\"\n    Decode date and time field.\n\n    The date code is a 32 bit value specifying the start time of the block.\n    Bits 0-16 contain the number of seconds since midnight,\n    and bits 17-31 the number of days since 17th November 1989.\n    \"\"\"\n    # prevent numpy array\n    days = int(data >> 17)\n    secs = int(data & 0x1FFFF)\n    starttime = UTCDateTime('1989-11-17') + days * 86400 + secs\n    return starttime\n\n\ndef read_data_block(f, headonly=False, channel_prefix=\"HH\", **kwargs):\n    \"\"\"\n    Read one data block from GCF file.\n\n    more details can be found here:\n    http://geophysics.eas.gatech.edu/GTEQ/Scream4.4/GCF_Specification.htm\n    f - file object to read from\n    if skipData is True, Only header is returned.\n    if not a data block (SPS=0) - returns None.\n    \"\"\"\n    # get ID\n    sysid = f.read(4)\n    if not sysid:\n        raise EOFError  # got to EOF\n    sysid, = struct.unpack('>I', sysid)\n    if sysid >> 31 & 0b1 > 0:\n        sysid = (sysid << 6) >> 6\n    sysid = decode36(sysid)\n    # get Stream ID\n    stid, = struct.unpack('>I', f.read(4))\n    stid = decode36(stid)\n    # get Date & Time\n    data, = struct.unpack('>I', f.read(4))\n    starttime = decode_date_time(data)\n    # get data format\n    # get reserved, SPS, data type compression,\n    # number of 32bit records (num_records)\n    reserved, sps, compress, num_records = struct.unpack('>4B', f.read(4))\n    compression = compress & 0b00000111  # get compression code\n    t_offset = compress >> 4  # get time offset\n    if t_offset > 0:\n        starttime = starttime + t_offset / TIME_OFFSETS_D[sps]\n    if sps in SPS_D:\n        sps = SPS_D[sps]  # get special SPS value if needed\n    if not sps:\n        f.seek(num_records * 4, 1)  # skip if not a data block\n        if 1008 - num_records * 4 > 0:\n            # keep skipping to get 1008 record\n            f.seek(1008 - num_records * 4, 1)\n        return None\n    npts = num_records * compression  # number of samples\n    header = {}\n    header['starttime'] = starttime\n    header['station'] = stid[:-2]\n    header['channel'] = (channel_prefix[:2] + stid[-2]).upper()\n    header['sampling_rate'] = float(sps)\n    header['npts'] = npts\n    if headonly:\n        f.seek(4 * (num_records + 2), 1)  # skip data part (inc. FIC and RIC)\n        # skip to end of block if only partly filled with data\n        if 1000 - num_records * 4 > 0:\n            f.seek(1000 - num_records * 4, 1)\n        return header\n    else:\n        # get FIC\n        fic, = struct.unpack('>i', f.read(4))\n        # get incremental data\n        data = struct.unpack(f'>{npts}{COMPRESSION_D[compression]}',\n                             f.read(4 * num_records))\n        # construct time series\n        data = (fic + np.cumsum(data)).astype('i4')\n        # get RIC\n        ric, = struct.unpack('>i', f.read(4))\n        # skip to end of block if only partly filled with data\n        if 1000 - num_records * 4 > 0:\n            f.seek(1000 - num_records * 4, 1)\n        # verify last data sample matches RIC\n        if not data[-1] == ric:\n            raise ValueError(\"Last sample mismatch with RIC\")\n        return header, data\n\n\ndef read_header(f, **kwargs):\n    \"\"\"\n    Reads header only from GCF file.\n    \"\"\"\n    return read_data_block(f, headonly=True, **kwargs)\n\n\ndef read(f, **kwargs):\n    \"\"\"\n    Reads header and data from GCF file.\n    \"\"\"\n    return read_data_block(f, headonly=False, **kwargs)\n", "path": "obspy/io/gcf/libgcf.py"}]}