File Coverage

BUFR.xs
Criterion Covered Total %
statement 83 87 95.4
branch 38 46 82.6
condition n/a
subroutine n/a
pod n/a
total 121 133 90.9


line stmt bran cond sub pod time code
1             /* Copyright (C) 2010-2023 MET Norway */
2             /* This module is free software; you can redistribute it and/or */
3             /* modify it under the same terms as Perl itself. */
4              
5             #include "EXTERN.h"
6             #include "perl.h"
7             #include "XSUB.h"
8              
9             static unsigned char SetFirstBits[] = {
10             0,
11             0x80, 0xc0, 0xe0, 0xf0,
12             0xf8, 0xfc, 0xfe, 0xff
13             };
14             static unsigned char SetLastBits[] = {
15             0,
16             0x01, 0x03, 0x07, 0x0f,
17             0x1f, 0x3f, 0x7f, 0xff
18             };
19              
20             MODULE = Geo::BUFR PACKAGE = Geo::BUFR
21              
22             double
23             bitstream2dec(unsigned char *bitstream, \
24             int bitpos, int wordlength)
25              
26             PROTOTYPE: $$$
27             CODE:
28             /* Extract wordlength bits from bitstream, starting at bitpos. */
29             /* The extracted bits is interpreted as a non negative integer. */
30             /* Returns undef if all bits extracted are 1 bits. */
31              
32             static unsigned int bitmask[] = {
33             0,
34             0x00000001, 0x00000003, 0x00000007, 0x0000000f,
35             0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
36             0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
37             0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
38             0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
39             0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
40             0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
41             0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff
42             };
43 12438           int octet = bitpos/8; /* Which octet the word starts in */
44 12438           int startbit = bitpos & 0x07; /* Offset from start of octet to start of word */
45             int bits, lastbits;
46             unsigned long word;
47              
48 12438 50         if (wordlength == 0) {
49 0           word = 0;
50 12438 50         } else if (wordlength > 32) {
51             /* For now, we restrict ourselves to 32-bit words */
52 0           XSRETURN_UNDEF;
53             } else {
54 12438 100         if (wordlength+startbit <= 8) {
55             /* Word to be extracted is within a single octet */
56 3601           word = bitstream[octet] >> (8-wordlength-startbit);
57 3601           word &= bitmask[wordlength];
58             } else {
59             /* Extract bits in first octet */
60 8837           bits = 8-startbit;
61 8837           word = bitstream[octet++] & bitmask[bits];
62             /* Extract complete octets */
63 13813 100         while (wordlength-bits >= 8) {
64 4976           word = (word << 8) | bitstream[octet++];
65 4976           bits += 8;
66             }
67             /* Extract remaining bits */
68 8837           lastbits = wordlength-bits;
69 8837 100         if (lastbits > 0) {
70 8306           word <<= lastbits;
71 8306           word |= (bitstream[octet] >> (8-lastbits)) & bitmask[lastbits];
72             }
73             }
74             /* If word contains all ones, it is undefined */
75 12438 100         if (word == bitmask[wordlength]) {
76 3909           XSRETURN_UNDEF;
77             }
78             }
79              
80 8529           RETVAL = word;
81              
82             OUTPUT:
83             RETVAL
84              
85              
86             SV *
87             bitstream2ascii(unsigned char *bitstream, int bitpos, int len)
88              
89             PROTOTYPE: $$$
90             CODE:
91             /* Extract len bytes from bitstream, starting at bitpos, and */
92             /* interpret the extracted bytes as an ascii string. Return */
93             /* undef if the extracted bytes are all 1 bits */
94              
95 90           int octet = bitpos/8;
96 90           int lshift = bitpos & 0x07;
97 90           unsigned char str[len+1];
98             int rshift, missing, i;
99             SV *ascii;
100              
101 90 100         if (lshift == 0) {
102 239 100         for (i = 0; i < len; i++)
103 226           str[i] = bitstream[octet+i];
104             } else {
105 77           rshift = 8-lshift;
106 1094 100         for (i = 0; i < len; i++) {
107 2034           str[i] = (bitstream[octet+i ] << lshift) |
108 1017           (bitstream[octet+i+1] >> rshift);
109             }
110             }
111 90           str[len] = '\0';
112              
113             /* Check for missing value, i.e, all bits are ones */
114 90           missing = 1;
115 1333 100         for (i = 0; i < len; i++) {
116 1243 50         if (str[i] != 0xff) {
117 1243           missing = 0;
118             }
119             }
120 90 50         if (missing == 1) {
121 0           XSRETURN_UNDEF;
122             }
123              
124 90           ascii = newSVpv((char*)str, len);
125 90           RETVAL = ascii;
126              
127             OUTPUT:
128             RETVAL
129              
130              
131             void
132             dec2bitstream(unsigned long word, \
133             unsigned char *bitstream, \
134             int bitpos, int wordlength)
135              
136             PROTOTYPE: $$$$
137             CODE:
138             /* Encode non negative integer value word in wordlength bits in bitstream, */
139             /* starting at bit bitpos. Last byte will be padded with 1 bits */
140              
141 5671           int octet = bitpos/8; /* Which octet the word should start in */
142 5671           int startbit = bitpos & 0x07; /* Offset from start of octet to start of word */
143             int num_encodedbits, num_onebits, num_lastbits, i;
144             unsigned char lastbyte;
145              
146 5671 50         if (wordlength > 32) {
147             /* Data width in table B for numerical data will hopefully never
148             exceed 32. Since 'long' in C is assured to be 4 bytes, we are
149             not able to encode that big values with present method. */
150 0           exit(1);
151             }
152 5671 50         if (wordlength > 0) {
153             /* First set the bits after startbit to 0 in first byte of bitstream */
154 5671           bitstream[octet] &= SetFirstBits[startbit];
155 5671 100         if (wordlength+startbit <= 32) {
156             /* Shift the part of word we want to encode (the last wordlength bits)
157             so that it starts at startbit in first byte (will be preceded by 0 bits) */
158 5650           word <<= (32-wordlength-startbit);
159             /* Then extract first byte, which must be shifted to last byte
160             before being assigned to an unsigned char */
161 5650           bitstream[octet] |= word >> 24;
162             /* Then encode remaining bytes in word, if any */
163 5650           num_encodedbits = 8-startbit;
164 10182 100         while (num_encodedbits < wordlength) {
165 4532           word <<= 8;
166 4532           bitstream[++octet] = word >> 24;
167 4532           num_encodedbits += 8;
168             }
169             /* Finally pad last encoded byte in bitstream with one bits */
170 5650           num_onebits = (8 - (startbit + wordlength)) & 0x07;
171 5650           bitstream[octet] |= SetLastBits[num_onebits];
172             } else {
173             /* When aligning word with bitstream[octet], we will in this
174             case lose some of the rightmost bits, which we therefore need
175             to save first */
176 21           num_lastbits = startbit+wordlength-32;
177 21           lastbyte = word << (8-num_lastbits);
178             /* Align word with bitstream[octet] */
179 21           word >>= num_lastbits;
180             /* Then extract and encode the bytes in word, which must be
181             shifted to last byte before being assigned to an unsigned
182             char */
183 21           bitstream[octet++] |= word >> 24;
184 21           word <<= 8;
185 84 100         for (i=0; i<3; i++) {
186 63           bitstream[octet++] = word >> 24;
187 63           word <<= 8;
188             }
189             /* Finally encode last bits (which we shifted off from word above),
190             padded with one bits */
191 21           bitstream[octet] = lastbyte | SetLastBits[8-num_lastbits];
192             }
193             }
194              
195              
196             void
197             ascii2bitstream(unsigned char *ascii, \
198             unsigned char *bitstream, \
199             int bitpos, int width)
200              
201             PROTOTYPE: $$$$
202             CODE:
203             /* Encode ASCII string ascii in width bytes in bitstream, starting at */
204             /* bit bitpos. Last byte will be padded with 1 bits */
205              
206 35           int octet = bitpos/8; /* Which octet the word should start in */
207 35           int startbit = bitpos & 0x07; /* Offset from start of octet to start of word */
208             int lshift, i;
209              
210 35 50         if (width > 0) {
211 35 100         if (startbit == 0) {
212             /* The easy case: just copy byte for byte */
213 56 100         for (i = 0; i < width; i++)
214 50           bitstream[octet+i] = ascii[i];
215             } else {
216 29           lshift = 8-startbit;
217             /* First byte should be first startbit bits of first bitstream byte,
218             then first 8-startbit bits of first byte of ascii byte */
219 58           bitstream[octet] = (bitstream[octet] & SetFirstBits[startbit]) |
220 29           (ascii[0] >> startbit);
221             /* Next bytes should be last startbit bits of previous ascii byte,
222             then first 8-startbit bits of next ascii byte */
223 457 100         for (i = 1; i < width; i++)
224 428           bitstream[octet+i] = (ascii[i-1] << lshift) | (ascii[i] >> startbit);
225             /* Last byte should be remaining startbit bits of last ascii byte,
226             padded with 8-startbit one bits */
227 29           bitstream[octet+width] = (ascii[width-1] << lshift) | SetLastBits[8-startbit];
228             }
229             }
230              
231              
232             void
233             null2bitstream(unsigned char *bitstream, \
234             int bitpos, int wordlength)
235              
236             PROTOTYPE: $$$$
237             CODE:
238             /* Set wordlength bits in bitstream starting at bit bitpos to 0 */
239             /* bits. Last byte will be padded with 1 bits */
240              
241 23           int octet = bitpos/8; /* Which octet the word should start in */
242 23           int startbit = bitpos & 0x07; /* Offset from start of octet to start of word */
243             int bits, num_onebits;
244              
245 23 50         if (wordlength > 0) {
246             /* First set the bits after startbit to 0 in first byte of bitstream */
247 23           bitstream[octet] &= SetFirstBits[startbit];
248 23           bits = 8 - startbit;
249 47 100         while (wordlength-bits > 0) {
250 24           bitstream[++octet] = 0x00;
251 24           bits += 8;
252             }
253             /* Finally pad last encoded byte in bitstream with one bits */
254 23           num_onebits = (8 - (startbit + wordlength)) & 0x07;
255 23           bitstream[octet] |= SetLastBits[num_onebits];
256             }