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