1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the MetadataSegment class.
4 : *
5 : * This class is used to manage access to the SYS METADATA segment. This
6 : * segment holds all the metadata for objects in the PCIDSK file.
7 : *
8 : * This class is closely partnered with the MetadataSet class.
9 : *
10 : ******************************************************************************
11 : * Copyright (c) 2009
12 : * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
13 : *
14 : * Permission is hereby granted, free of charge, to any person obtaining a
15 : * copy of this software and associated documentation files (the "Software"),
16 : * to deal in the Software without restriction, including without limitation
17 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 : * and/or sell copies of the Software, and to permit persons to whom the
19 : * Software is furnished to do so, subject to the following conditions:
20 : *
21 : * The above copyright notice and this permission notice shall be included
22 : * in all copies or substantial portions of the Software.
23 : *
24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 : * DEALINGS IN THE SOFTWARE.
31 : ****************************************************************************/
32 :
33 : #include "pcidsk_file.h"
34 : #include "segment/metadatasegment.h"
35 : #include <cassert>
36 : #include <cstring>
37 : #include <cstdio>
38 :
39 : using namespace PCIDSK;
40 :
41 : /************************************************************************/
42 : /* MetadataSegment() */
43 : /************************************************************************/
44 :
45 25 : MetadataSegment::MetadataSegment( PCIDSKFile *file, int segment,
46 : const char *segment_pointer )
47 25 : : CPCIDSKSegment( file, segment, segment_pointer )
48 :
49 : {
50 25 : loaded = false;
51 25 : }
52 :
53 : /************************************************************************/
54 : /* ~MetadataSegment() */
55 : /************************************************************************/
56 :
57 50 : MetadataSegment::~MetadataSegment()
58 :
59 : {
60 25 : if( loaded && update_list.size() > 0 )
61 20 : Save();
62 50 : }
63 :
64 : /************************************************************************/
65 : /* Load() */
66 : /************************************************************************/
67 :
68 35 : void MetadataSegment::Load()
69 :
70 : {
71 35 : if( loaded )
72 10 : return;
73 :
74 : // TODO: this should likely be protected by a mutex.
75 :
76 : /* -------------------------------------------------------------------- */
77 : /* Load the segment contents into a buffer. */
78 : /* -------------------------------------------------------------------- */
79 25 : seg_data.SetSize( data_size - 1024 );
80 :
81 25 : ReadFromFile( seg_data.buffer, 0, data_size - 1024 );
82 :
83 25 : loaded = true;
84 : }
85 :
86 : /************************************************************************/
87 : /* FetchMetadata() */
88 : /************************************************************************/
89 :
90 11 : void MetadataSegment::FetchMetadata( const char *group, int id,
91 : std::map<std::string,std::string> &md_set)
92 :
93 : {
94 : /* -------------------------------------------------------------------- */
95 : /* Load the metadata segment if not already loaded. */
96 : /* -------------------------------------------------------------------- */
97 11 : Load();
98 :
99 : /* -------------------------------------------------------------------- */
100 : /* Establish the key prefix we are searching for. */
101 : /* -------------------------------------------------------------------- */
102 : char key_prefix[200];
103 : int prefix_len;
104 :
105 11 : sprintf( key_prefix, "METADATA_%s_%d_", group, id );
106 11 : prefix_len = strlen(key_prefix);
107 :
108 : /* -------------------------------------------------------------------- */
109 : /* Process all the metadata entries in this segment, searching */
110 : /* for those that match our prefix. */
111 : /* -------------------------------------------------------------------- */
112 : const char *pszNext;
113 :
114 58 : for( pszNext = (const char *) seg_data.buffer; *pszNext != '\0'; )
115 : {
116 : /* -------------------------------------------------------------------- */
117 : /* Identify the end of this line, and the split character (:). */
118 : /* -------------------------------------------------------------------- */
119 36 : int i_split = -1, i;
120 :
121 4304 : for( i=0;
122 3210 : pszNext[i] != 10 && pszNext[i] != 12 && pszNext[i] != 0;
123 : i++)
124 : {
125 1058 : if( i_split == -1 && pszNext[i] == ':' )
126 36 : i_split = i;
127 : }
128 :
129 36 : if( pszNext[i] == '\0' )
130 0 : break;
131 :
132 : /* -------------------------------------------------------------------- */
133 : /* If this matches our prefix, capture the key and value. */
134 : /* -------------------------------------------------------------------- */
135 36 : if( i_split != -1 && strncmp(pszNext,key_prefix,prefix_len) == 0 )
136 : {
137 14 : std::string key, value;
138 :
139 14 : key.assign( pszNext+prefix_len, i_split-prefix_len );
140 :
141 14 : if( pszNext[i_split+1] == ' ' )
142 14 : value.assign( pszNext+i_split+2, i-i_split-2 );
143 : else
144 0 : value.assign( pszNext+i_split+1, i-i_split-1 );
145 :
146 14 : md_set[key] = value;
147 : }
148 :
149 : /* -------------------------------------------------------------------- */
150 : /* Advance to start of next line. */
151 : /* -------------------------------------------------------------------- */
152 36 : pszNext = pszNext + i;
153 108 : while( *pszNext == 10 || *pszNext == 12 )
154 36 : pszNext++;
155 : }
156 11 : }
157 :
158 : /************************************************************************/
159 : /* SetMetadataValue() */
160 : /************************************************************************/
161 :
162 24 : void MetadataSegment::SetMetadataValue( const char *group, int id,
163 : const std::string& key, const std::string& value )
164 :
165 : {
166 24 : Load();
167 :
168 : char key_prefix[200];
169 :
170 24 : sprintf( key_prefix, "METADATA_%s_%d_", group, id );
171 :
172 24 : std::string full_key;
173 :
174 24 : full_key = key_prefix;
175 24 : full_key += key;
176 :
177 24 : update_list[full_key] = value;
178 24 : }
179 :
180 : /************************************************************************/
181 : /* Save() */
182 : /* */
183 : /* When saving we first need to merge in any updates. We put */
184 : /* this off since scanning and updating the metadata doc could */
185 : /* be epxensive if done for each item. */
186 : /************************************************************************/
187 :
188 20 : void MetadataSegment::Save()
189 :
190 : {
191 20 : std::string new_data;
192 :
193 : /* -------------------------------------------------------------------- */
194 : /* Process all the metadata entries in this segment, searching */
195 : /* for those that match our prefix. */
196 : /* -------------------------------------------------------------------- */
197 : const char *pszNext;
198 :
199 36 : for( pszNext = (const char *) seg_data.buffer; *pszNext != '\0'; )
200 : {
201 : /* -------------------------------------------------------------------- */
202 : /* Identify the end of this line, and the split character (:). */
203 : /* -------------------------------------------------------------------- */
204 16 : int i_split = -1, i;
205 :
206 1588 : for( i=0;
207 1183 : pszNext[i] != 10 && pszNext[i] != 12 && pszNext[i] != 0;
208 : i++)
209 : {
210 389 : if( i_split == -1 && pszNext[i] == ':' )
211 16 : i_split = i;
212 : }
213 :
214 16 : if( pszNext[i] == '\0' )
215 0 : break;
216 :
217 : /* -------------------------------------------------------------------- */
218 : /* If we have a new value for this key, do not copy over the */
219 : /* old value. Otherwise append the old value to our new image. */
220 : /* -------------------------------------------------------------------- */
221 16 : std::string full_key;
222 :
223 16 : full_key.assign( pszNext, i_split );
224 :
225 16 : if( update_list.count(full_key) == 1 )
226 : /* do not transfer - we will append later */;
227 : else
228 15 : new_data.append( pszNext, i+1 );
229 :
230 : /* -------------------------------------------------------------------- */
231 : /* Advance to start of next line. */
232 : /* -------------------------------------------------------------------- */
233 16 : pszNext = pszNext + i;
234 48 : while( *pszNext == 10 || *pszNext == 12 )
235 16 : pszNext++;
236 : }
237 :
238 : /* -------------------------------------------------------------------- */
239 : /* Append all the update items with non-empty values. */
240 : /* -------------------------------------------------------------------- */
241 20 : std::map<std::string,std::string>::iterator it;
242 :
243 43 : for( it = update_list.begin(); it != update_list.end(); it++ )
244 : {
245 24 : if( it->second.size() == 0 )
246 1 : continue;
247 :
248 23 : std::string line;
249 :
250 23 : line = it->first;
251 23 : line += ": ";
252 23 : line += it->second;
253 23 : line += "\n";
254 :
255 23 : new_data += line;
256 : }
257 :
258 20 : update_list.clear();
259 :
260 : /* -------------------------------------------------------------------- */
261 : /* Move the new value into our buffer, and write to disk. */
262 : /* -------------------------------------------------------------------- */
263 20 : if( new_data.size() % 512 != 0 ) // zero fill the last block.
264 : {
265 : new_data.resize( new_data.size() + (512 - (new_data.size() % 512)),
266 20 : '\0' );
267 : }
268 :
269 20 : seg_data.SetSize( new_data.size() );
270 20 : memcpy( seg_data.buffer, new_data.c_str(), new_data.size() );
271 :
272 20 : WriteToFile( seg_data.buffer, 0, seg_data.buffer_size );
273 20 : }
|