1 : /******************************************************************************
2 : * $Id: gdalmultidomainmetadata.cpp 22798 2011-07-24 12:19:53Z rouault $
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 : #include <map>
34 :
35 : CPL_CVSID("$Id: gdalmultidomainmetadata.cpp 22798 2011-07-24 12:19:53Z rouault $");
36 :
37 : /************************************************************************/
38 : /* GDALMultiDomainMetadata() */
39 : /************************************************************************/
40 :
41 1122976 : GDALMultiDomainMetadata::GDALMultiDomainMetadata()
42 :
43 : {
44 1122976 : papszDomainList = NULL;
45 1122976 : papoMetadataLists = NULL;
46 1122976 : }
47 :
48 : /************************************************************************/
49 : /* ~GDALMultiDomainMetadata() */
50 : /************************************************************************/
51 :
52 1120525 : GDALMultiDomainMetadata::~GDALMultiDomainMetadata()
53 :
54 : {
55 1120525 : Clear();
56 1120525 : }
57 :
58 : /************************************************************************/
59 : /* Clear() */
60 : /************************************************************************/
61 :
62 1120525 : void GDALMultiDomainMetadata::Clear()
63 :
64 : {
65 : int i, nDomainCount;
66 :
67 1120525 : nDomainCount = CSLCount( papszDomainList );
68 1120525 : CSLDestroy( papszDomainList );
69 1120525 : papszDomainList = NULL;
70 :
71 1202875 : for( i = 0; i < nDomainCount; i++ )
72 : {
73 82350 : delete papoMetadataLists[i];
74 : }
75 1120525 : CPLFree( papoMetadataLists );
76 1120525 : papoMetadataLists = NULL;
77 1120525 : }
78 :
79 :
80 : /************************************************************************/
81 : /* GetMetadata() */
82 : /************************************************************************/
83 :
84 16772 : char **GDALMultiDomainMetadata::GetMetadata( const char *pszDomain )
85 :
86 : {
87 16772 : if( pszDomain == NULL )
88 856 : pszDomain = "";
89 :
90 16772 : int iDomain = CSLFindString( papszDomainList, pszDomain );
91 :
92 16772 : if( iDomain == -1 )
93 9004 : return NULL;
94 : else
95 7768 : return papoMetadataLists[iDomain]->List();
96 : }
97 :
98 : /************************************************************************/
99 : /* SetMetadata() */
100 : /************************************************************************/
101 :
102 85079 : CPLErr GDALMultiDomainMetadata::SetMetadata( char **papszMetadata,
103 : const char *pszDomain )
104 :
105 : {
106 85079 : if( pszDomain == NULL )
107 279 : pszDomain = "";
108 :
109 85079 : int iDomain = CSLFindString( papszDomainList, pszDomain );
110 :
111 85079 : if( iDomain == -1 )
112 : {
113 : int nDomainCount;
114 :
115 84782 : papszDomainList = CSLAddString( papszDomainList, pszDomain );
116 84782 : nDomainCount = CSLCount( papszDomainList );
117 :
118 : papoMetadataLists = (CPLStringList **)
119 84782 : CPLRealloc( papoMetadataLists, sizeof(void*)*(nDomainCount+1) );
120 84782 : papoMetadataLists[nDomainCount] = NULL;
121 84782 : papoMetadataLists[nDomainCount-1] = new CPLStringList();
122 84782 : iDomain = nDomainCount-1;
123 : }
124 :
125 85079 : papoMetadataLists[iDomain]->Assign( CSLDuplicate( papszMetadata ) );
126 :
127 : // we want to mark name/value pair domains as being sorted for fast
128 : // access.
129 85079 : if( !EQUALN(pszDomain,"xml:",4) && !EQUAL(pszDomain, "SUBDATASETS") )
130 84981 : papoMetadataLists[iDomain]->Sort();
131 :
132 85079 : return CE_None;
133 : }
134 :
135 : /************************************************************************/
136 : /* GetMetadataItem() */
137 : /************************************************************************/
138 :
139 65001 : const char *GDALMultiDomainMetadata::GetMetadataItem( const char *pszName,
140 : const char *pszDomain )
141 :
142 : {
143 65001 : if( pszDomain == NULL )
144 1184 : pszDomain = "";
145 :
146 65001 : int iDomain = CSLFindString( papszDomainList, pszDomain );
147 :
148 65001 : if( iDomain == -1 )
149 42999 : return NULL;
150 : else
151 22002 : return papoMetadataLists[iDomain]->FetchNameValue( pszName );
152 : }
153 :
154 : /************************************************************************/
155 : /* SetMetadataItem() */
156 : /************************************************************************/
157 :
158 355169 : CPLErr GDALMultiDomainMetadata::SetMetadataItem( const char *pszName,
159 : const char *pszValue,
160 : const char *pszDomain )
161 :
162 : {
163 355169 : if( pszDomain == NULL )
164 157 : pszDomain = "";
165 :
166 : /* -------------------------------------------------------------------- */
167 : /* Create the domain if it does not already exist. */
168 : /* -------------------------------------------------------------------- */
169 355169 : int iDomain = CSLFindString( papszDomainList, pszDomain );
170 :
171 355169 : if( iDomain == -1 )
172 : {
173 80870 : SetMetadata( NULL, pszDomain );
174 80870 : iDomain = CSLFindString( papszDomainList, pszDomain );
175 : }
176 :
177 : /* -------------------------------------------------------------------- */
178 : /* Set the value in the domain list. */
179 : /* -------------------------------------------------------------------- */
180 355169 : papoMetadataLists[iDomain]->SetNameValue( pszName, pszValue );
181 :
182 355169 : return CE_None;
183 : }
184 :
185 : /************************************************************************/
186 : /* XMLInit() */
187 : /* */
188 : /* This method should be invoked on the parent of the */
189 : /* <Metadata> elements. */
190 : /************************************************************************/
191 :
192 1884 : int GDALMultiDomainMetadata::XMLInit( CPLXMLNode *psTree, int bMerge )
193 :
194 : {
195 : CPLXMLNode *psMetadata;
196 :
197 : /* ==================================================================== */
198 : /* Process all <Metadata> elements, each for one domain. */
199 : /* ==================================================================== */
200 8405 : for( psMetadata = psTree->psChild;
201 : psMetadata != NULL; psMetadata = psMetadata->psNext )
202 : {
203 : CPLXMLNode *psMDI;
204 : const char *pszDomain, *pszFormat;
205 :
206 6521 : if( psMetadata->eType != CXT_Element
207 : || !EQUAL(psMetadata->pszValue,"Metadata") )
208 5674 : continue;
209 :
210 847 : pszDomain = CPLGetXMLValue( psMetadata, "domain", "" );
211 847 : pszFormat = CPLGetXMLValue( psMetadata, "format", "" );
212 :
213 : // Make sure we have a CPLStringList for this domain,
214 : // without wiping out an existing one.
215 847 : if( GetMetadata( pszDomain ) == NULL )
216 518 : SetMetadata( NULL, pszDomain );
217 :
218 847 : int iDomain = CSLFindString( papszDomainList, pszDomain );
219 847 : CPLAssert( iDomain != -1 );
220 :
221 847 : CPLStringList *poMDList = papoMetadataLists[iDomain];
222 :
223 : /* -------------------------------------------------------------------- */
224 : /* XML format subdocuments. */
225 : /* -------------------------------------------------------------------- */
226 847 : if( EQUAL(pszFormat,"xml") )
227 : {
228 : CPLXMLNode *psSubDoc;
229 :
230 : /* find first non-attribute child of current element */
231 9 : psSubDoc = psMetadata->psChild;
232 36 : while( psSubDoc != NULL && psSubDoc->eType == CXT_Attribute )
233 18 : psSubDoc = psSubDoc->psNext;
234 :
235 9 : char *pszDoc = CPLSerializeXMLTree( psSubDoc );
236 :
237 9 : poMDList->AddStringDirectly( pszDoc );
238 : }
239 :
240 : /* -------------------------------------------------------------------- */
241 : /* Name value format. */
242 : /* <MDI key="...">value_Text</MDI> */
243 : /* -------------------------------------------------------------------- */
244 : else
245 : {
246 4732 : for( psMDI = psMetadata->psChild; psMDI != NULL;
247 : psMDI = psMDI->psNext )
248 : {
249 3894 : if( !EQUAL(psMDI->pszValue,"MDI")
250 : || psMDI->eType != CXT_Element
251 : || psMDI->psChild == NULL
252 : || psMDI->psChild->psNext == NULL
253 : || psMDI->psChild->eType != CXT_Attribute
254 : || psMDI->psChild->psChild == NULL )
255 1275 : continue;
256 :
257 2619 : char* pszName = psMDI->psChild->psChild->pszValue;
258 2619 : char* pszValue = psMDI->psChild->psNext->pszValue;
259 2619 : if( pszName != NULL && pszValue != NULL )
260 2619 : poMDList->SetNameValue( pszName, pszValue );
261 : }
262 : }
263 : }
264 :
265 1884 : return CSLCount(papszDomainList) != 0;
266 : }
267 :
268 : /************************************************************************/
269 : /* Serialize() */
270 : /************************************************************************/
271 :
272 2331 : CPLXMLNode *GDALMultiDomainMetadata::Serialize()
273 :
274 : {
275 2331 : CPLXMLNode *psFirst = NULL;
276 :
277 5883 : for( int iDomain = 0;
278 2335 : papszDomainList != NULL && papszDomainList[iDomain] != NULL;
279 : iDomain++)
280 : {
281 1217 : char **papszMD = papoMetadataLists[iDomain]->List();
282 : CPLXMLNode *psMD;
283 1217 : int bFormatXML = FALSE;
284 :
285 1217 : psMD = CPLCreateXMLNode( NULL, CXT_Element, "Metadata" );
286 :
287 1217 : if( strlen( papszDomainList[iDomain] ) > 0 )
288 : CPLCreateXMLNode(
289 : CPLCreateXMLNode( psMD, CXT_Attribute, "domain" ),
290 214 : CXT_Text, papszDomainList[iDomain] );
291 :
292 1217 : if( EQUALN(papszDomainList[iDomain],"xml:",4)
293 : && CSLCount(papszMD) == 1 )
294 : {
295 6 : CPLXMLNode *psValueAsXML = CPLParseXMLString( papszMD[0] );
296 6 : if( psValueAsXML != NULL )
297 : {
298 6 : bFormatXML = TRUE;
299 :
300 : CPLCreateXMLNode(
301 : CPLCreateXMLNode( psMD, CXT_Attribute, "format" ),
302 6 : CXT_Text, "xml" );
303 :
304 6 : CPLAddXMLChild( psMD, psValueAsXML );
305 : }
306 : }
307 :
308 1217 : if( !bFormatXML )
309 : {
310 1211 : CPLXMLNode* psLastChild = NULL;
311 1211 : if( psMD->psChild != NULL )
312 : {
313 208 : psLastChild = psMD->psChild;
314 416 : while( psLastChild->psNext != NULL )
315 0 : psLastChild = psLastChild->psNext;
316 : }
317 5191 : for( int i = 0; papszMD != NULL && papszMD[i] != NULL; i++ )
318 : {
319 : const char *pszRawValue;
320 3980 : char *pszKey = NULL;
321 : CPLXMLNode *psMDI;
322 :
323 3980 : pszRawValue = CPLParseNameValue( papszMD[i], &pszKey );
324 :
325 3980 : psMDI = CPLCreateXMLNode( NULL, CXT_Element, "MDI" );
326 3980 : if( psLastChild == NULL )
327 776 : psMD->psChild = psMDI;
328 : else
329 3204 : psLastChild->psNext = psMDI;
330 3980 : psLastChild = psMDI;
331 :
332 3980 : CPLSetXMLValue( psMDI, "#key", pszKey );
333 3980 : CPLCreateXMLNode( psMDI, CXT_Text, pszRawValue );
334 :
335 3980 : CPLFree( pszKey );
336 : }
337 : }
338 :
339 1217 : if( psFirst == NULL )
340 1118 : psFirst = psMD;
341 : else
342 99 : CPLAddXMLSibling( psFirst, psMD );
343 : }
344 :
345 2331 : return psFirst;
346 : }
347 :
|