File Coverage

BUFR.xs
Criterion Covered Total %
statement 74 87 85.0
branch 37 48 77.0
condition n/a
subroutine n/a
pod n/a
total 111 135 82.2


line stmt bran cond sub pod time code
1             /* Copyright (C) 2010-2025 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 UV bitmask[] = {
33             0,
34             0x0000000000000001, 0x0000000000000003, 0x0000000000000007, 0x000000000000000f,
35             0x000000000000001f, 0x000000000000003f, 0x000000000000007f, 0x00000000000000ff,
36             0x00000000000001ff, 0x00000000000003ff, 0x00000000000007ff, 0x0000000000000fff,
37             0x0000000000001fff, 0x0000000000003fff, 0x0000000000007fff, 0x000000000000ffff,
38             0x000000000001ffff, 0x000000000003ffff, 0x000000000007ffff, 0x00000000000fffff,
39             0x00000000001fffff, 0x00000000003fffff, 0x00000000007fffff, 0x0000000000ffffff,
40             0x0000000001ffffff, 0x0000000003ffffff, 0x0000000007ffffff, 0x000000000fffffff,
41             0x000000001fffffff, 0x000000003fffffff, 0x000000007fffffff, 0x00000000ffffffff,
42             0x00000001ffffffff, 0x00000003ffffffff, 0x00000007ffffffff, 0x0000000fffffffff,
43             0x0000001fffffffff, 0x0000003fffffffff, 0x0000007fffffffff, 0x000000ffffffffff,
44             0x000001ffffffffff, 0x000003ffffffffff, 0x000007ffffffffff, 0x00000fffffffffff,
45             0x00001fffffffffff, 0x00003fffffffffff, 0x00007fffffffffff, 0x0000ffffffffffff,
46             0x0001ffffffffffff, 0x0003ffffffffffff, 0x0007ffffffffffff, 0x000fffffffffffff,
47             0x001fffffffffffff, 0x003fffffffffffff, 0x007fffffffffffff, 0x00ffffffffffffff,
48             0x01ffffffffffffff, 0x03ffffffffffffff, 0x07ffffffffffffff, 0x0fffffffffffffff,
49             0x1fffffffffffffff, 0x3fffffffffffffff, 0x7fffffffffffffff, 0xffffffffffffffff
50             };
51 12454           int octet = bitpos/8; /* Which octet the word starts in */
52 12454           int startbit = bitpos & 0x07; /* Offset from start of octet to start of word */
53             int bits, lastbits;
54             UV word;
55              
56 12454 50         if (wordlength == 0) {
57 0           word = 0;
58 12454 50         } else if (wordlength > 64) {
59             /* For now, we restrict ourselves to 64-bit words */
60 0           XSRETURN_UNDEF;
61             } else {
62 12454 100         if (wordlength+startbit <= 8) {
63             /* Word to be extracted is within a single octet */
64 3602           word = bitstream[octet] >> (8-wordlength-startbit);
65 3602           word &= bitmask[wordlength];
66             } else {
67             /* Extract bits in first octet */
68 8852           bits = 8-startbit;
69 8852           word = bitstream[octet++] & bitmask[bits];
70             /* Extract complete octets */
71 13865 100         while (wordlength-bits >= 8) {
72 5013           word = (word << 8) | bitstream[octet++];
73 5013           bits += 8;
74             }
75             /* Extract remaining bits */
76 8852           lastbits = wordlength-bits;
77 8852 100         if (lastbits > 0) {
78 8319           word <<= lastbits;
79 8319           word |= (bitstream[octet] >> (8-lastbits)) & bitmask[lastbits];
80             }
81             }
82             /* If word contains all ones, it is undefined */
83 12454 100         if (word == bitmask[wordlength]) {
84 3910           XSRETURN_UNDEF;
85             }
86             }
87              
88 8544 100         RETVAL = word;
89              
90             OUTPUT:
91             RETVAL
92              
93              
94             SV *
95             bitstream2ascii(unsigned char *bitstream, int bitpos, int len)
96              
97             PROTOTYPE: $$$
98             CODE:
99             /* Extract len bytes from bitstream, starting at bitpos, and */
100             /* interpret the extracted bytes as an ascii string. Return */
101             /* undef if the extracted bytes are all 1 bits */
102              
103 90           int octet = bitpos/8;
104 90           int lshift = bitpos & 0x07;
105 90           unsigned char str[len+1];
106             int rshift, missing, i;
107             SV *ascii;
108              
109 90 100         if (lshift == 0) {
110 239 100         for (i = 0; i < len; i++)
111 226           str[i] = bitstream[octet+i];
112             } else {
113 77           rshift = 8-lshift;
114 1094 100         for (i = 0; i < len; i++) {
115 1017           str[i] = (bitstream[octet+i ] << lshift) |
116 1017           (bitstream[octet+i+1] >> rshift);
117             }
118             }
119 90           str[len] = '\0';
120              
121             /* Check for missing value, i.e, all bits are ones */
122 90           missing = 1;
123 1333 100         for (i = 0; i < len; i++) {
124 1243 50         if (str[i] != 0xff) {
125 1243           missing = 0;
126             }
127             }
128 90 50         if (missing == 1) {
129 0           XSRETURN_UNDEF;
130             }
131              
132 90           ascii = newSVpv((char*)str, len);
133 90           RETVAL = ascii;
134              
135             OUTPUT:
136             RETVAL
137              
138              
139             void
140             dec2bitstream(UV word, \
141             unsigned char *bitstream, \
142             int bitpos, int wordlength)
143              
144             PROTOTYPE: $$$$
145             CODE:
146             /* Encode non negative integer value word in wordlength bits in bitstream, */
147             /* starting at bit bitpos. Last byte will be padded with 1 bits */
148              
149 5713           int octet = bitpos/8; /* Which octet the word should start in */
150 5713           int startbit = bitpos & 0x07; /* Offset from start of octet to start of word */
151             int num_encodedbits, num_onebits, num_lastbits, i;
152             unsigned char lastbyte;
153              
154 5713 50         if (wordlength > 64) {
155             /* Data width in table B for numerical data (or after applying
156             CHANGE DATA WIDTH operator) will hopefully never exceed 64. We
157             are not able to encode that big values with present method. */
158 0           exit(1);
159             }
160 5713 50         if (wordlength > 0) {
161             /* First set the bits after startbit to 0 in first byte of bitstream */
162 5713           bitstream[octet] &= SetFirstBits[startbit];
163 5713 50         if (wordlength+startbit <= 64) {
164             /* Shift the part of word we want to encode (the last wordlength bits)
165             so that it starts at startbit in first byte (will be preceded by 0 bits) */
166 5713           word <<= (64-wordlength-startbit);
167             /* Then extract first byte, which must be shifted to last byte
168             before being assigned to an unsigned char */
169 5713           bitstream[octet] |= word >> 56;
170             /* Then encode remaining bytes in word, if any */
171 5713           num_encodedbits = 8-startbit;
172 10375 100         while (num_encodedbits < wordlength) {
173 4662           word <<= 8;
174 4662           bitstream[++octet] = word >> 56;
175 4662           num_encodedbits += 8;
176             }
177             /* Finally pad last encoded byte in bitstream with one bits */
178 5713           num_onebits = (8 - (startbit + wordlength)) & 0x07;
179 5713           bitstream[octet] |= SetLastBits[num_onebits];
180             } else {
181             /* When aligning word with bitstream[octet], we will in this
182             case lose some of the rightmost bits, which we therefore need
183             to save first */
184 0           num_lastbits = startbit+wordlength-64;
185 0           lastbyte = word << (8-num_lastbits);
186             /* Align word with bitstream[octet] */
187 0           word >>= num_lastbits;
188             /* Then extract and encode the bytes in word, which must be
189             shifted to last byte before being assigned to an unsigned
190             char */
191 0           bitstream[octet++] |= word >> 56;
192 0           word <<= 8;
193 0 0         for (i=0; i<3; i++) {
194 0           bitstream[octet++] = word >> 56;
195 0           word <<= 8;
196             }
197             /* Finally encode last bits (which we shifted off from word above),
198             padded with one bits */
199 0           bitstream[octet] = lastbyte | SetLastBits[8-num_lastbits];
200             }
201             }
202              
203              
204             void
205             ascii2bitstream(unsigned char *ascii, \
206             unsigned char *bitstream, \
207             int bitpos, int width)
208              
209             PROTOTYPE: $$$$
210             CODE:
211             /* Encode ASCII string ascii in width bytes in bitstream, starting at */
212             /* bit bitpos. Last byte will be padded with 1 bits */
213              
214 35           int octet = bitpos/8; /* Which octet the word should start in */
215 35           int startbit = bitpos & 0x07; /* Offset from start of octet to start of word */
216             int lshift, i;
217              
218 35 50         if (width > 0) {
219 35 100         if (startbit == 0) {
220             /* The easy case: just copy byte for byte */
221 56 100         for (i = 0; i < width; i++)
222 50           bitstream[octet+i] = ascii[i];
223             } else {
224 29           lshift = 8-startbit;
225             /* First byte should be first startbit bits of first bitstream byte,
226             then first 8-startbit bits of first byte of ascii byte */
227 29           bitstream[octet] = (bitstream[octet] & SetFirstBits[startbit]) |
228 29           (ascii[0] >> startbit);
229             /* Next bytes should be last startbit bits of previous ascii byte,
230             then first 8-startbit bits of next ascii byte */
231 457 100         for (i = 1; i < width; i++)
232 428           bitstream[octet+i] = (ascii[i-1] << lshift) | (ascii[i] >> startbit);
233             /* Last byte should be remaining startbit bits of last ascii byte,
234             padded with 8-startbit one bits */
235 29           bitstream[octet+width] = (ascii[width-1] << lshift) | SetLastBits[8-startbit];
236             }
237             }
238              
239              
240             void
241             null2bitstream(unsigned char *bitstream, \
242             int bitpos, int wordlength)
243              
244             PROTOTYPE: $$$$
245             CODE:
246             /* Set wordlength bits in bitstream starting at bit bitpos to 0 */
247             /* bits. Last byte will be padded with 1 bits */
248              
249 24           int octet = bitpos/8; /* Which octet the word should start in */
250 24           int startbit = bitpos & 0x07; /* Offset from start of octet to start of word */
251             int bits, num_onebits;
252              
253 24 50         if (wordlength > 0) {
254             /* First set the bits after startbit to 0 in first byte of bitstream */
255 24           bitstream[octet] &= SetFirstBits[startbit];
256 24           bits = 8 - startbit;
257 48 100         while (wordlength-bits > 0) {
258 24           bitstream[++octet] = 0x00;
259 24           bits += 8;
260             }
261             /* Finally pad last encoded byte in bitstream with one bits */
262 24           num_onebits = (8 - (startbit + wordlength)) & 0x07;
263 24           bitstream[octet] |= SetLastBits[num_onebits];
264             }