1 : /******************************************************************************
2 : * $Id: gdalmultidomainmetadata.cpp 17282 2009-06-22 19:19:46Z warmerdam $
3 : *
4 : * Project: GDAL Core
5 : * Purpose: Implementation of GDALMultiDomainMetadata class. This class
6 : * manages metadata items for a variable list of domains.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "gdal_pam.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: gdalmultidomainmetadata.cpp 17282 2009-06-22 19:19:46Z warmerdam $");
35 :
36 : /************************************************************************/
37 : /* GDALMultiDomainMetadata() */
38 : /************************************************************************/
39 :
40 1079158 : GDALMultiDomainMetadata::GDALMultiDomainMetadata()
41 :
42 : {
43 1079158 : papszDomainList = NULL;
44 1079158 : papapszMetadataLists = NULL;
45 1079158 : }
46 :
47 : /************************************************************************/
48 : /* ~GDALMultiDomainMetadata() */
49 : /************************************************************************/
50 :
51 1077909 : GDALMultiDomainMetadata::~GDALMultiDomainMetadata()
52 :
53 : {
54 1077909 : Clear();
55 1077909 : }
56 :
57 : /************************************************************************/
58 : /* Clear() */
59 : /************************************************************************/
60 :
61 1077909 : void GDALMultiDomainMetadata::Clear()
62 :
63 : {
64 : int i, nDomainCount;
65 :
66 1077909 : nDomainCount = CSLCount( papszDomainList );
67 1077909 : CSLDestroy( papszDomainList );
68 1077909 : papszDomainList = NULL;
69 :
70 1126775 : for( i = 0; i < nDomainCount; i++ )
71 : {
72 48866 : CSLDestroy( papapszMetadataLists[i] );
73 : }
74 1077909 : CPLFree( papapszMetadataLists );
75 1077909 : papapszMetadataLists = NULL;
76 1077909 : }
77 :
78 :
79 : /************************************************************************/
80 : /* GetMetadata() */
81 : /************************************************************************/
82 :
83 43833 : char **GDALMultiDomainMetadata::GetMetadata( const char *pszDomain )
84 :
85 : {
86 43833 : if( pszDomain == NULL )
87 328 : pszDomain = "";
88 :
89 43833 : int iDomain = CSLFindString( papszDomainList, pszDomain );
90 :
91 43833 : if( iDomain == -1 )
92 25480 : return NULL;
93 : else
94 18353 : return papapszMetadataLists[iDomain];
95 : }
96 :
97 : /************************************************************************/
98 : /* SetMetadata() */
99 : /************************************************************************/
100 :
101 : CPLErr GDALMultiDomainMetadata::SetMetadata( char **papszMetadata,
102 2945 : const char *pszDomain )
103 :
104 : {
105 2945 : if( pszDomain == NULL )
106 0 : pszDomain = "";
107 :
108 2945 : int iDomain = CSLFindString( papszDomainList, pszDomain );
109 :
110 2945 : if( iDomain == -1 )
111 : {
112 : int nDomainCount;
113 :
114 2452 : papszDomainList = CSLAddString( papszDomainList, pszDomain );
115 2452 : nDomainCount = CSLCount( papszDomainList );
116 :
117 : papapszMetadataLists = (char ***)
118 2452 : CPLRealloc( papapszMetadataLists, sizeof(char*)*(nDomainCount+1) );
119 2452 : papapszMetadataLists[nDomainCount] = NULL;
120 2452 : papapszMetadataLists[nDomainCount-1] = CSLDuplicate( papszMetadata );
121 : }
122 : else
123 : {
124 493 : CSLDestroy( papapszMetadataLists[iDomain] );
125 493 : papapszMetadataLists[iDomain] = CSLDuplicate( papszMetadata );
126 : }
127 :
128 2945 : return CE_None;
129 : }
130 :
131 : /************************************************************************/
132 : /* GetMetadataItem() */
133 : /************************************************************************/
134 :
135 : const char *GDALMultiDomainMetadata::GetMetadataItem( const char *pszName,
136 33444 : const char *pszDomain )
137 :
138 : {
139 33444 : char **papszMD = GetMetadata( pszDomain );
140 33444 : if( papszMD != NULL )
141 13168 : return CSLFetchNameValue( papszMD, pszName );
142 : else
143 20276 : return NULL;
144 : }
145 :
146 : /************************************************************************/
147 : /* SetMetadataItem() */
148 : /************************************************************************/
149 :
150 : CPLErr GDALMultiDomainMetadata::SetMetadataItem( const char *pszName,
151 : const char *pszValue,
152 175886 : const char *pszDomain )
153 :
154 : {
155 175886 : if( pszDomain == NULL )
156 1 : pszDomain = "";
157 :
158 175886 : int iDomain = CSLFindString( papszDomainList, pszDomain );
159 :
160 : /* -------------------------------------------------------------------- */
161 : /* Create the domain if it does not already exist. */
162 : /* -------------------------------------------------------------------- */
163 175886 : if( iDomain == -1 )
164 : {
165 : int nDomainCount;
166 :
167 47651 : papszDomainList = CSLAddString( papszDomainList, pszDomain );
168 47651 : nDomainCount = CSLCount( papszDomainList );
169 :
170 : papapszMetadataLists = (char ***)
171 47651 : CPLRealloc( papapszMetadataLists, sizeof(char*)*(nDomainCount+1) );
172 47651 : papapszMetadataLists[nDomainCount] = NULL;
173 47651 : iDomain = nDomainCount-1;
174 47651 : papapszMetadataLists[iDomain] = NULL;
175 : }
176 :
177 : /* -------------------------------------------------------------------- */
178 : /* Set the value in the domain list. */
179 : /* -------------------------------------------------------------------- */
180 175886 : if( pszValue != NULL )
181 : {
182 : papapszMetadataLists[iDomain] =
183 : CSLSetNameValue( papapszMetadataLists[iDomain],
184 175886 : pszName, pszValue );
185 : }
186 :
187 : /* -------------------------------------------------------------------- */
188 : /* Remove the target key from the domain list. */
189 : /* -------------------------------------------------------------------- */
190 : else
191 : {
192 0 : int iKey = CSLFindName( papapszMetadataLists[iDomain], pszName );
193 :
194 0 : if( iKey != -1 )
195 : papapszMetadataLists[iDomain] =
196 0 : CSLRemoveStrings(papapszMetadataLists[iDomain],iKey,1,NULL);
197 : }
198 :
199 175886 : return CE_None;
200 : }
201 :
202 : /************************************************************************/
203 : /* XMLInit() */
204 : /* */
205 : /* This method should be invoked on the parent of the */
206 : /* <Metadata> elements. */
207 : /************************************************************************/
208 :
209 1198 : int GDALMultiDomainMetadata::XMLInit( CPLXMLNode *psTree, int bMerge )
210 :
211 : {
212 : CPLXMLNode *psMetadata;
213 :
214 : /* ==================================================================== */
215 : /* Process all <Metadata> elements, each for one domain. */
216 : /* ==================================================================== */
217 5080 : for( psMetadata = psTree->psChild;
218 : psMetadata != NULL; psMetadata = psMetadata->psNext )
219 : {
220 3882 : char **papszMD = NULL;
221 : CPLXMLNode *psMDI;
222 : const char *pszDomain, *pszFormat;
223 :
224 3882 : if( psMetadata->eType != CXT_Element
225 : || !EQUAL(psMetadata->pszValue,"Metadata") )
226 3343 : continue;
227 :
228 539 : pszDomain = CPLGetXMLValue( psMetadata, "domain", "" );
229 539 : pszFormat = CPLGetXMLValue( psMetadata, "format", "" );
230 :
231 : /* -------------------------------------------------------------------- */
232 : /* XML format subdocuments. */
233 : /* -------------------------------------------------------------------- */
234 539 : if( EQUAL(pszFormat,"xml") )
235 : {
236 : CPLXMLNode *psSubDoc;
237 :
238 : /* find first non-attribute child of current element */
239 3 : psSubDoc = psMetadata->psChild;
240 12 : while( psSubDoc != NULL && psSubDoc->eType == CXT_Attribute )
241 6 : psSubDoc = psSubDoc->psNext;
242 :
243 3 : char *pszDoc = CPLSerializeXMLTree( psSubDoc );
244 :
245 3 : papszMD = (char **) CPLCalloc(sizeof(char*),2);
246 3 : papszMD[0] = pszDoc;
247 : }
248 :
249 : /* -------------------------------------------------------------------- */
250 : /* Name value format. */
251 : /* <MDI key="...">value_Text</MDI> */
252 : /* -------------------------------------------------------------------- */
253 : else
254 : {
255 536 : if( bMerge )
256 : {
257 536 : papszMD = GetMetadata( pszDomain );
258 536 : if( papszMD != NULL )
259 277 : papszMD = CSLDuplicate( papszMD );
260 : }
261 :
262 3754 : for( psMDI = psMetadata->psChild; psMDI != NULL;
263 : psMDI = psMDI->psNext )
264 : {
265 3218 : if( !EQUAL(psMDI->pszValue,"MDI")
266 : || psMDI->eType != CXT_Element
267 : || psMDI->psChild == NULL
268 : || psMDI->psChild->psNext == NULL
269 : || psMDI->psChild->eType != CXT_Attribute
270 : || psMDI->psChild->psChild == NULL )
271 1180 : continue;
272 :
273 : papszMD =
274 : CSLSetNameValue( papszMD,
275 : psMDI->psChild->psChild->pszValue,
276 2038 : psMDI->psChild->psNext->pszValue );
277 : }
278 : }
279 :
280 539 : SetMetadata( papszMD, pszDomain );
281 539 : CSLDestroy( papszMD );
282 : }
283 :
284 1198 : return CSLCount(papszDomainList) != 0;
285 : }
286 :
287 : /************************************************************************/
288 : /* Serialize() */
289 : /************************************************************************/
290 :
291 1758 : CPLXMLNode *GDALMultiDomainMetadata::Serialize()
292 :
293 : {
294 1758 : CPLXMLNode *psFirst = NULL;
295 :
296 2603 : for( int iDomain = 0;
297 : papszDomainList != NULL && papszDomainList[iDomain] != NULL;
298 : iDomain++)
299 : {
300 845 : char **papszMD = papapszMetadataLists[iDomain];
301 : CPLXMLNode *psMD;
302 845 : int bFormatXML = FALSE;
303 :
304 845 : psMD = CPLCreateXMLNode( NULL, CXT_Element, "Metadata" );
305 :
306 845 : if( strlen( papszDomainList[iDomain] ) > 0 )
307 : CPLCreateXMLNode(
308 : CPLCreateXMLNode( psMD, CXT_Attribute, "domain" ),
309 154 : CXT_Text, papszDomainList[iDomain] );
310 :
311 845 : if( EQUALN(papszDomainList[iDomain],"xml:",4)
312 : && CSLCount(papszMD) == 1 )
313 : {
314 1 : CPLXMLNode *psValueAsXML = CPLParseXMLString( papszMD[0] );
315 1 : if( psValueAsXML != NULL )
316 : {
317 1 : bFormatXML = TRUE;
318 :
319 : CPLCreateXMLNode(
320 : CPLCreateXMLNode( psMD, CXT_Attribute, "format" ),
321 1 : CXT_Text, "xml" );
322 :
323 1 : CPLAddXMLChild( psMD, psValueAsXML );
324 : }
325 : }
326 :
327 845 : if( !bFormatXML )
328 : {
329 4142 : for( int i = 0; papszMD != NULL && papszMD[i] != NULL; i++ )
330 : {
331 : const char *pszRawValue;
332 : char *pszKey;
333 : CPLXMLNode *psMDI;
334 :
335 3298 : pszRawValue = CPLParseNameValue( papszMD[i], &pszKey );
336 :
337 3298 : psMDI = CPLCreateXMLNode( psMD, CXT_Element, "MDI" );
338 3298 : CPLSetXMLValue( psMDI, "#key", pszKey );
339 3298 : CPLCreateXMLNode( psMDI, CXT_Text, pszRawValue );
340 :
341 3298 : CPLFree( pszKey );
342 : }
343 : }
344 :
345 845 : if( psFirst == NULL )
346 780 : psFirst = psMD;
347 : else
348 65 : CPLAddXMLSibling( psFirst, psMD );
349 : }
350 :
351 1758 : return psFirst;
352 : }
353 :
|