NCEPLIBS-bufr 11.7.1
stndrd.f
Go to the documentation of this file.
1C> @file
2C> @brief Standardize a BUFR message.
3
4C> This subroutine performs the same function as subroutine stdmsg(),
5C> except that it operates on a BUFR message passed in via a memory array
6C> and returns its output via a separate memory array,
7C> whereas stdmsg() operates on BUFR messages stored internally
8C> within the software.
9C>
10C> @author J. Ator
11C> @date 2004-08-18
12C>
13C> @param[in] LUNIT -- integer: Fortran logical unit number for
14C> BUFR file
15C> @param[in] MSGIN -- integer(*): BUFR message
16C> @param[in] LMSGOT -- integer: Dimensioned size (in integers) of
17C> MSGOT; used by the subroutine to ensure that
18C> it doesn't overflow the MSGOT array
19C> @param[out] MSGOT -- integer(*): Standardized copy of MSGIN
20C>
21C> @remarks
22C> - MSGIN and MSGOT must be separate arrays.
23C> - Standardized messages are usually longer in length than their
24C> non-standard counterparts, so it's usually a good idea to allow
25C> for extra space when allocating MSGOT within the application program.
26C>
27C> <b>Program history log:</b>
28C> | Date | Programmer | Comments |
29C> | -----|------------|----------|
30C> | 2004-08-18 | J. Ator | Original author |
31C> | 2005-11-29 | J. Ator | Use getlens() and iupbs01(); ensure that byte 4 of Section 4 is zeroed out in MSGOT; check edition number of BUFR message before padding to an even byte count |
32C> | 2009-03-23 | J. Ator | Use iupbs3() and nemtbax(); don't assume that compressed messages are already fully standardized within Section 3 |
33C> | 2014-02-04 | J. Ator | Account for subsets with byte count > 65530 |
34C> | 2020-07-16 | J. Ator | Fix bug in ISLEN computation when NSUB = 1 |
35C>
36 SUBROUTINE stndrd(LUNIT,MSGIN,LMSGOT,MSGOT)
37
38 USE modv_maxnc
39
40 dimension icd(maxnc)
41
42 COMMON /hrdwrd/ nbytw,nbitw,iord(8)
43
44 dimension msgin(*),msgot(*)
45
46 CHARACTER*128 BORT_STR
47 CHARACTER*8 SUBSET
48 CHARACTER*4 SEVN
49 CHARACTER*1 TAB
50
51 LOGICAL FOUND
52
53C-----------------------------------------------------------------------
54C-----------------------------------------------------------------------
55
56C LUNIT MUST POINT TO AN OPEN BUFR FILE
57C -------------------------------------
58
59 CALL status(lunit,lun,il,im)
60 IF(il.EQ.0) GOTO 900
61
62C IDENTIFY THE SECTION LENGTHS AND ADDRESSES IN MSGIN
63C ---------------------------------------------------
64
65 CALL getlens(msgin,5,len0,len1,len2,len3,len4,len5)
66
67 iad3 = len0+len1+len2
68 iad4 = iad3+len3
69
70 lenn = len0+len1+len2+len3+len4+len5
71
72 lenm = iupbs01(msgin,'LENM')
73
74 IF(lenn.NE.lenm) GOTO 901
75
76 mbit = (lenn-4)*8
77 CALL upc(sevn,4,msgin,mbit,.true.)
78 IF(sevn.NE.'7777') GOTO 902
79
80C COPY SECTIONS 0 THROUGH PART OF SECTION 3 INTO MSGOT
81C ----------------------------------------------------
82
83 mxbyto = (lmsgot*nbytw) - 8
84
85 lbyto = iad3+7
86 IF(lbyto.GT.mxbyto) GOTO 905
87 CALL mvb(msgin,1,msgot,1,lbyto)
88
89C REWRITE NEW SECTION 3 IN A "STANDARD" FORM
90C ------------------------------------------
91
92C LOCATE THE TOP-LEVEL TABLE A DESCRIPTOR
93
94 found = .false.
95 ii = 10
96 DO WHILE ((.NOT.found).AND.(ii.GE.8))
97 isub = iupb(msgin,iad3+ii,16)
98 CALL numtab(lun,isub,subset,tab,itab)
99 IF((itab.NE.0).AND.(tab.EQ.'D')) THEN
100 CALL nemtbax(lun,subset,mtyp,msbt,inod)
101 IF(inod.NE.0) found = .true.
102 ENDIF
103 ii = ii - 2
104 ENDDO
105 IF(.NOT.found) GOTO 903
106
107 IF (istdesc(isub).EQ.0) THEN
108
109C ISUB IS A NON-STANDARD TABLE A DESCRIPTOR AND NEEDS
110C TO BE EXPANDED INTO AN EQUIVALENT STANDARD SEQUENCE
111
112 CALL restd(lun,isub,ncd,icd)
113 ELSE
114
115C ISUB IS ALREADY A STANDARD DESCRIPTOR, SO JUST COPY
116C IT "AS IS" INTO THE NEW SECTION 3 (I.E. NO EXPANSION
117C IS NECESSARY!)
118
119 ncd = 1
120 icd(ncd) = isub
121 ENDIF
122
123C USE THE EDITION NUMBER TO DETERMINE THE LENGTH OF THE
124C NEW SECTION 3
125
126 len3 = 7+(ncd*2)
127 iben = iupbs01(msgin,'BEN')
128 IF(iben.LT.4) THEN
129 len3 = len3+1
130 ENDIF
131 lbyto = lbyto + len3 - 7
132 IF(lbyto.GT.mxbyto) GOTO 905
133
134C STORE THE DESCRIPTORS INTO THE NEW SECTION 3
135
136 ibit = (iad3+7)*8
137 DO n=1,ncd
138 CALL pkb(icd(n),16,msgot,ibit)
139 ENDDO
140
141C DEPENDING ON THE EDITION NUMBER, PAD OUT THE NEW SECTION 3 WITH AN
142C ADDITIONAL ZEROED-OUT BYTE IN ORDER TO ENSURE AN EVEN BYTE COUNT
143
144 IF(iben.LT.4) THEN
145 CALL pkb(0,8,msgot,ibit)
146 ENDIF
147
148C STORE THE LENGTH OF THE NEW SECTION 3
149
150 ibit = iad3*8
151 CALL pkb(len3,24,msgot,ibit)
152
153C NOW THE TRICKY PART - NEW SECTION 4
154C -----------------------------------
155
156 IF(iupbs3(msgin,'ICMP').EQ.1) THEN
157
158C THE DATA IN SECTION 4 IS COMPRESSED AND IS THEREFORE ALREADY
159C STANDARDIZED, SO COPY IT "AS IS" INTO THE NEW SECTION 4
160
161 IF((lbyto+len4+4).GT.mxbyto) GOTO 905
162
163 CALL mvb(msgin,iad4+1,msgot,lbyto+1,len4)
164
165 jbit = (lbyto+len4)*8
166
167 ELSE
168
169 nad4 = iad3+len3
170
171 ibit = (iad4+4)*8
172 jbit = (nad4+4)*8
173
174 lbyto = lbyto + 4
175
176C COPY THE SUBSETS, MINUS THE BYTE COUNTERS AND BIT PADS, INTO
177C THE NEW SECTION 4
178
179 nsub = iupbs3(msgin,'NSUB')
180
181 DO 10 i=1,nsub
182 CALL upb(lsub,16,msgin,ibit)
183 IF(nsub.GT.1) THEN
184
185C USE THE BYTE COUNTER TO COPY THIS SUBSET
186
187 islen = lsub-2
188 ELSE
189
190C THIS IS THE ONLY SUBSET IN THE MESSAGE, AND IT COULD
191C POSSIBLY BE AN OVERLARGE (> 65530 BYTES) SUBSET, IN
192C WHICH CASE WE CAN'T RELY ON THE VALUE STORED IN THE
193C BYTE COUNTER. EITHER WAY, WE DON'T REALLY NEED IT.
194
195 islen = iad4+len4-(ibit/8)
196 IF (mod(len4,2).EQ.0) islen = islen - 1
197 ENDIF
198 DO l=1,islen
199 CALL upb(nval,8,msgin,ibit)
200 lbyto = lbyto + 1
201 IF(lbyto.GT.mxbyto) GOTO 905
202 CALL pkb(nval,8,msgot,jbit)
203 ENDDO
204 DO k=1,8
205 kbit = ibit-k-8
206 CALL upb(kval,8,msgin,kbit)
207 IF(kval.EQ.k) THEN
208 jbit = jbit-k-8
209 GOTO 10
210 ENDIF
211 ENDDO
212 GOTO 904
21310 ENDDO
214
215C FROM THIS POINT ON, WE WILL NEED (AT MOST) 6 MORE BYTES OF
216C SPACE WITHIN MSGOT IN ORDER TO BE ABLE TO STORE THE ENTIRE
217C STANDARDIZED MESSAGE (I.E. WE WILL NEED (AT MOST) 2 MORE
218C ZEROED-OUT BYTES IN SECTION 4 PLUS THE 4 BYTES '7777' IN
219C SECTION 5), SO DO A FINAL MSGOT OVERFLOW CHECK NOW.
220
221 IF(lbyto+6.GT.mxbyto) GOTO 905
222
223C PAD THE NEW SECTION 4 WITH ZEROES UP TO THE NEXT WHOLE BYTE
224C BOUNDARY.
225
226 DO WHILE(.NOT.(mod(jbit,8).EQ.0))
227 CALL pkb(0,1,msgot,jbit)
228 ENDDO
229
230C DEPENDING ON THE EDITION NUMBER, WE MAY NEED TO FURTHER PAD
231C THE NEW SECTION 4 WITH AN ADDITIONAL ZEROED-OUT BYTE IN ORDER
232C TO ENSURE THAT THE PADDING IS UP TO AN EVEN BYTE BOUNDARY.
233
234 IF( (iben.LT.4) .AND. (mod(jbit/8,2).NE.0) ) THEN
235 CALL pkb(0,8,msgot,jbit)
236 ENDIF
237
238 ibit = nad4*8
239 len4 = jbit/8 - nad4
240 CALL pkb(len4,24,msgot,ibit)
241 CALL pkb(0,8,msgot,ibit)
242 ENDIF
243
244C FINISH THE NEW MESSAGE WITH AN UPDATED SECTION 0 BYTE COUNT
245C -----------------------------------------------------------
246
247 ibit = 32
248 lenn = len0+len1+len2+len3+len4+len5
249 CALL pkb(lenn,24,msgot,ibit)
250
251 CALL pkc('7777',4,msgot,jbit)
252
253C EXITS
254C -----
255
256 RETURN
257900 CALL bort('BUFRLIB: STNDRD - BUFR FILE IS CLOSED, IT MUST BE'//
258 . ' OPEN')
259901 WRITE(bort_str,'("BUFRLIB: STNDRD - INPUT MESSAGE LENGTH FROM'//
260 . ' SECTION 0",I6," DOES NOT EQUAL SUM OF ALL INDIVIDUAL SECTION'//
261 . ' LENGTHS (",I6,")")') lenm,lenn
262 CALL bort(bort_str)
263902 WRITE(bort_str,'("BUFRLIB: STNDRD - INPUT MESSAGE DOES NOT '//
264 . 'END WITH ""7777"" (ENDS WITH ",A)') sevn
265 CALL bort(bort_str)
266903 CALL bort('BUFRLIB: STNDRD - TABLE A SUBSET DESCRIPTOR '//
267 . 'NOT FOUND')
268904 CALL bort('BUFRLIB: STNDRD - BIT MISMATCH COPYING SECTION 4 '//
269 . 'FROM INPUT TO OUTPUT (STANDARD) MESSAGE')
270905 CALL bort('BUFRLIB: STNDRD - OVERFLOW OF OUTPUT (STANDARD) '//
271 . 'MESSAGE ARRAY; TRY A LARGER DIMENSION FOR THIS ARRAY')
272 END
subroutine bort(STR)
This subroutine calls subroutine errwrt() to log an error message, then calls subroutine bort_exit() ...
Definition: bort.f:23
subroutine getlens(MBAY, LL, LEN0, LEN1, LEN2, LEN3, LEN4, LEN5)
This subroutine reads the lengths of all of the individual sections of a given BUFR message,...
Definition: getlens.f:40
function istdesc(IDN)
Given the bit-wise (integer) representation of a descriptor, this function determines whether the des...
Definition: istdesc.f:26
function iupb(MBAY, NBYT, NBIT)
THIS FUNCTION UNPACKS AND RETURNS A BINARY INTEGER WORD CONTAINED WITHIN NBIT BITS OF A BUFR MESSAGE ...
Definition: iupb.f:37
function iupbs01(MBAY, S01MNEM)
This function returns a specified value from within Section 0 or Section 1 of a BUFR message.
Definition: iupbs01.f:74
function iupbs3(MBAY, S3MNEM)
This function returns a specified value from within Section 3 of a BUFR message.
Definition: iupbs3.f:35
subroutine mvb(IB1, NB1, IB2, NB2, NBM)
THIS SUBROUTINE COPIES A SPECIFIED NUMBER OF BYTES FROM ONE PACKED BINARY ARRAY TO ANOTHER.
Definition: mvb.f:44
This module declares and initializes the MAXNC variable.
Definition: modv_MAXNC.f90:9
integer, parameter, public maxnc
Maximum number of descriptors within Section 3 of a BUFR message.
Definition: modv_MAXNC.f90:14
subroutine nemtbax(LUN, NEMO, MTYP, MSBT, INOD)
This subroutine searches for a descriptor within Table A of the internal DX BUFR tables.
Definition: nemtbax.f:34
subroutine numtab(LUN, IDN, NEMO, TAB, IRET)
This subroutine returns information about a descriptor from the internal DX BUFR tables,...
Definition: numtab.f:59
subroutine pkb(NVAL, NBITS, IBAY, IBIT)
This subroutine encodes an integer value within a specified number of bits of an integer array,...
Definition: pkb.f:39
subroutine pkc(CHR, NCHR, IBAY, IBIT)
This subroutine encodes a character string within a specified number of bits of an integer array,...
Definition: pkc.f:41
void restd(f77int *lun, f77int *tddesc, f77int *nctddesc, f77int ctddesc[])
Given the bit-wise (integer) representation of a local (not WMO-standard) Table D descriptor,...
Definition: restd.c:43
subroutine status(LUNIT, LUN, IL, IM)
This subroutine checks whether a specified Fortran logical unit number is currently connected to the ...
Definition: status.f:56
subroutine stndrd(LUNIT, MSGIN, LMSGOT, MSGOT)
This subroutine performs the same function as subroutine stdmsg(), except that it operates on a BUFR ...
Definition: stndrd.f:37
subroutine upb(NVAL, NBITS, IBAY, IBIT)
THIS SUBROUTINE UNPACKS AND RETURNS A BINARY INTEGER CONTAINED WITHIN NBITS BITS OF IBAY,...
Definition: upb.f:50
subroutine upc(CHR, NCHR, IBAY, IBIT, CNVNULL)
THIS SUBROUTINE UNPACKS AND RETURNS A CHARACTER STRING OF LENGTH NCHR CONTAINED WITHIN NCHR BYTES OF ...
Definition: upc.f:50