1 : /******************************************************************************
2 : * $Id: ddffield.cpp 10645 2007-01-18 02:22:39Z warmerdam $
3 : *
4 : * Project: ISO 8211 Access
5 : * Purpose: Implements the DDFField class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "iso8211.h"
31 : #include "cpl_conv.h"
32 :
33 : CPL_CVSID("$Id: ddffield.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
34 :
35 : // Note, we implement no constructor for this class to make instantiation
36 : // cheaper. It is required that the Initialize() be called before anything
37 : // else.
38 :
39 : /************************************************************************/
40 : /* Initialize() */
41 : /************************************************************************/
42 :
43 357600 : void DDFField::Initialize( DDFFieldDefn *poDefnIn, const char * pachDataIn,
44 : int nDataSizeIn )
45 :
46 : {
47 357600 : pachData = pachDataIn;
48 357600 : nDataSize = nDataSizeIn;
49 357600 : poDefn = poDefnIn;
50 357600 : }
51 :
52 : /************************************************************************/
53 : /* Dump() */
54 : /************************************************************************/
55 :
56 : /**
57 : * Write out field contents to debugging file.
58 : *
59 : * A variety of information about this field, and all it's
60 : * subfields is written to the given debugging file handle. Note that
61 : * field definition information (ala DDFFieldDefn) isn't written.
62 : *
63 : * @param fp The standard io file handle to write to. ie. stderr
64 : */
65 :
66 0 : void DDFField::Dump( FILE * fp )
67 :
68 : {
69 0 : int nMaxRepeat = 8;
70 :
71 0 : if( getenv("DDF_MAXDUMP") != NULL )
72 0 : nMaxRepeat = atoi(getenv("DDF_MAXDUMP"));
73 :
74 0 : fprintf( fp, " DDFField:\n" );
75 0 : fprintf( fp, " Tag = `%s'\n", poDefn->GetName() );
76 0 : fprintf( fp, " DataSize = %d\n", nDataSize );
77 :
78 0 : fprintf( fp, " Data = `" );
79 0 : for( int i = 0; i < MIN(nDataSize,40); i++ )
80 : {
81 0 : if( pachData[i] < 32 || pachData[i] > 126 )
82 0 : fprintf( fp, "\\%02X", ((unsigned char *) pachData)[i] );
83 : else
84 0 : fprintf( fp, "%c", pachData[i] );
85 : }
86 :
87 0 : if( nDataSize > 40 )
88 0 : fprintf( fp, "..." );
89 0 : fprintf( fp, "'\n" );
90 :
91 : /* -------------------------------------------------------------------- */
92 : /* dump the data of the subfields. */
93 : /* -------------------------------------------------------------------- */
94 0 : int iOffset = 0, nLoopCount;
95 :
96 0 : for( nLoopCount = 0; nLoopCount < GetRepeatCount(); nLoopCount++ )
97 : {
98 0 : if( nLoopCount > nMaxRepeat )
99 : {
100 0 : fprintf( fp, " ...\n" );
101 0 : break;
102 : }
103 :
104 0 : for( int i = 0; i < poDefn->GetSubfieldCount(); i++ )
105 : {
106 : int nBytesConsumed;
107 :
108 : poDefn->GetSubfield(i)->DumpData( pachData + iOffset,
109 0 : nDataSize - iOffset, fp );
110 :
111 : poDefn->GetSubfield(i)->GetDataLength( pachData + iOffset,
112 : nDataSize - iOffset,
113 0 : &nBytesConsumed );
114 :
115 0 : iOffset += nBytesConsumed;
116 : }
117 : }
118 0 : }
119 :
120 : /************************************************************************/
121 : /* GetSubfieldData() */
122 : /************************************************************************/
123 :
124 : /**
125 : * Fetch raw data pointer for a particular subfield of this field.
126 : *
127 : * The passed DDFSubfieldDefn (poSFDefn) should be acquired from the
128 : * DDFFieldDefn corresponding with this field. This is normally done
129 : * once before reading any records. This method involves a series of
130 : * calls to DDFSubfield::GetDataLength() in order to track through the
131 : * DDFField data to that belonging to the requested subfield. This can
132 : * be relatively expensive.<p>
133 : *
134 : * @param poSFDefn The definition of the subfield for which the raw
135 : * data pointer is desired.
136 : * @param pnMaxBytes The maximum number of bytes that can be accessed from
137 : * the returned data pointer is placed in this int, unless it is NULL.
138 : * @param iSubfieldIndex The instance of this subfield to fetch. Use zero
139 : * (the default) for the first instance.
140 : *
141 : * @return A pointer into the DDFField's data that belongs to the subfield.
142 : * This returned pointer is invalidated by the next record read
143 : * (DDFRecord::ReadRecord()) and the returned pointer should not be freed
144 : * by the application.
145 : */
146 :
147 105644 : const char *DDFField::GetSubfieldData( DDFSubfieldDefn *poSFDefn,
148 : int *pnMaxBytes, int iSubfieldIndex )
149 :
150 : {
151 105644 : int iOffset = 0;
152 :
153 105644 : if( poSFDefn == NULL )
154 0 : return NULL;
155 :
156 105644 : if( iSubfieldIndex > 0 && poDefn->GetFixedWidth() > 0 )
157 : {
158 308 : iOffset = poDefn->GetFixedWidth() * iSubfieldIndex;
159 308 : iSubfieldIndex = 0;
160 : }
161 :
162 211362 : while( iSubfieldIndex >= 0 )
163 : {
164 272610 : for( int iSF = 0; iSF < poDefn->GetSubfieldCount(); iSF++ )
165 : {
166 : int nBytesConsumed;
167 272536 : DDFSubfieldDefn * poThisSFDefn = poDefn->GetSubfield( iSF );
168 :
169 272536 : if( poThisSFDefn == poSFDefn && iSubfieldIndex == 0 )
170 : {
171 105644 : if( pnMaxBytes != NULL )
172 104952 : *pnMaxBytes = nDataSize - iOffset;
173 :
174 105644 : return pachData + iOffset;
175 : }
176 :
177 : poThisSFDefn->GetDataLength( pachData+iOffset, nDataSize - iOffset,
178 166892 : &nBytesConsumed);
179 166892 : iOffset += nBytesConsumed;
180 : }
181 :
182 74 : iSubfieldIndex--;
183 : }
184 :
185 : // We didn't find our target subfield or instance!
186 0 : return NULL;
187 : }
188 :
189 : /************************************************************************/
190 : /* GetRepeatCount() */
191 : /************************************************************************/
192 :
193 : /**
194 : * How many times do the subfields of this record repeat? This
195 : * will always be one for non-repeating fields.
196 : *
197 : * @return The number of times that the subfields of this record occur
198 : * in this record. This will be one for non-repeating fields.
199 : *
200 : * @see <a href="example.html">8211view example program</a>
201 : * for demonstation of handling repeated fields properly.
202 : */
203 :
204 252 : int DDFField::GetRepeatCount()
205 :
206 : {
207 252 : if( !poDefn->IsRepeating() )
208 0 : return 1;
209 :
210 : /* -------------------------------------------------------------------- */
211 : /* The occurance count depends on how many copies of this */
212 : /* field's list of subfields can fit into the data space. */
213 : /* -------------------------------------------------------------------- */
214 252 : if( poDefn->GetFixedWidth() )
215 : {
216 236 : return nDataSize / poDefn->GetFixedWidth();
217 : }
218 :
219 : /* -------------------------------------------------------------------- */
220 : /* Note that it may be legal to have repeating variable width */
221 : /* subfields, but I don't have any samples, so I ignore it for */
222 : /* now. */
223 : /* */
224 : /* The file data/cape_royal_AZ_DEM/1183XREF.DDF has a repeating */
225 : /* variable length field, but the count is one, so it isn't */
226 : /* much value for testing. */
227 : /* -------------------------------------------------------------------- */
228 16 : int iOffset = 0, iRepeatCount = 1;
229 :
230 20 : while( TRUE )
231 : {
232 112 : for( int iSF = 0; iSF < poDefn->GetSubfieldCount(); iSF++ )
233 : {
234 : int nBytesConsumed;
235 76 : DDFSubfieldDefn * poThisSFDefn = poDefn->GetSubfield( iSF );
236 :
237 76 : if( poThisSFDefn->GetWidth() > nDataSize - iOffset )
238 0 : nBytesConsumed = poThisSFDefn->GetWidth();
239 : else
240 : poThisSFDefn->GetDataLength( pachData+iOffset,
241 : nDataSize - iOffset,
242 76 : &nBytesConsumed);
243 :
244 76 : iOffset += nBytesConsumed;
245 76 : if( iOffset > nDataSize )
246 0 : return iRepeatCount - 1;
247 : }
248 :
249 36 : if( iOffset > nDataSize - 2 )
250 16 : return iRepeatCount;
251 :
252 20 : iRepeatCount++;
253 : }
254 : }
255 :
256 : /************************************************************************/
257 : /* GetInstanceData() */
258 : /************************************************************************/
259 :
260 : /**
261 : * Get field instance data and size.
262 : *
263 : * The returned data pointer and size values are suitable for use with
264 : * DDFRecord::SetFieldRaw().
265 : *
266 : * @param nInstance a value from 0 to GetRepeatCount()-1.
267 : * @param pnInstanceSize a location to put the size (in bytes) of the
268 : * field instance data returned. This size will include the unit terminator
269 : * (if any), but not the field terminator. This size pointer may be NULL
270 : * if not needed.
271 : *
272 : * @return the data pointer, or NULL on error.
273 : */
274 :
275 16 : const char *DDFField::GetInstanceData( int nInstance,
276 : int *pnInstanceSize )
277 :
278 : {
279 16 : int nRepeatCount = GetRepeatCount();
280 : const char *pachWrkData;
281 :
282 16 : if( nInstance < 0 || nInstance >= nRepeatCount )
283 0 : return NULL;
284 :
285 : /* -------------------------------------------------------------------- */
286 : /* Special case for fields without subfields (like "0001"). We */
287 : /* don't currently handle repeating simple fields. */
288 : /* -------------------------------------------------------------------- */
289 16 : if( poDefn->GetSubfieldCount() == 0 )
290 : {
291 0 : pachWrkData = GetData();
292 0 : if( pnInstanceSize != 0 )
293 0 : *pnInstanceSize = GetDataSize();
294 0 : return pachWrkData;
295 : }
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* Get a pointer to the start of the existing data for this */
299 : /* iteration of the field. */
300 : /* -------------------------------------------------------------------- */
301 : int nBytesRemaining1, nBytesRemaining2;
302 : DDFSubfieldDefn *poFirstSubfield;
303 :
304 16 : poFirstSubfield = poDefn->GetSubfield(0);
305 :
306 : pachWrkData = GetSubfieldData(poFirstSubfield, &nBytesRemaining1,
307 16 : nInstance);
308 :
309 : /* -------------------------------------------------------------------- */
310 : /* Figure out the size of the entire field instance, including */
311 : /* unit terminators, but not any trailing field terminator. */
312 : /* -------------------------------------------------------------------- */
313 16 : if( pnInstanceSize != NULL )
314 : {
315 : DDFSubfieldDefn *poLastSubfield;
316 : int nLastSubfieldWidth;
317 : const char *pachLastData;
318 :
319 16 : poLastSubfield = poDefn->GetSubfield(poDefn->GetSubfieldCount()-1);
320 :
321 : pachLastData = GetSubfieldData( poLastSubfield, &nBytesRemaining2,
322 16 : nInstance );
323 : poLastSubfield->GetDataLength( pachLastData, nBytesRemaining2,
324 16 : &nLastSubfieldWidth );
325 :
326 : *pnInstanceSize =
327 16 : nBytesRemaining1 - (nBytesRemaining2 - nLastSubfieldWidth);
328 : }
329 :
330 16 : return pachWrkData;
331 : }
|