-
-
Notifications
You must be signed in to change notification settings - Fork 56.5k
Expand file tree
/
Copy pathpersistence_c.cpp
More file actions
1479 lines (1249 loc) · 43.4 KB
/
persistence_c.cpp
File metadata and controls
1479 lines (1249 loc) · 43.4 KB
Edit and raw actions
OlderNewer
1
// This file is part of OpenCV project.
2
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
// of this distribution and at http://opencv.org/license.html
4
5
6
#include "precomp.hpp"
7
#include "persistence.hpp"
8
9
static inline bool cv_strcasecmp(const char * s1, const char * s2)
10
{
11
if ( s1 == 0 && s2 == 0 )
12
return true;
13
else if ( s1 == 0 || s2 == 0 )
14
return false;
15
16
size_t len1 = strlen(s1);
17
size_t len2 = strlen(s2);
18
if ( len1 != len2 )
19
return false;
20
21
for ( size_t i = 0U; i < len1; i++ )
22
if ( tolower( static_cast<int>(s1[i]) ) != tolower( static_cast<int>(s2[i]) ) )
23
return false;
24
25
return true;
26
}
27
28
// this function will convert "aa?bb&cc&dd" to {"aa", "bb", "cc", "dd"}
29
static std::vector<std::string> analyze_file_name( std::string const & file_name )
30
{
31
static const char not_file_name = '\n';
32
static const char parameter_begin = '?';
33
static const char parameter_separator = '&';
34
std::vector<std::string> result;
35
36
if ( file_name.find(not_file_name, 0U) != std::string::npos )
37
return result;
38
39
size_t beg = file_name.find_last_of(parameter_begin);
40
size_t end = file_name.size();
41
result.push_back(file_name.substr(0U, beg));
42
43
if ( beg != std::string::npos )
44
{
45
beg ++;
46
for ( size_t param_beg = beg, param_end = beg;
47
param_end < end;
48
param_beg = param_end + 1U )
49
{
50
param_end = file_name.find_first_of( parameter_separator, param_beg );
51
if ( (param_end == std::string::npos || param_end != param_beg) && param_beg + 1U < end )
52
{
53
result.push_back( file_name.substr( param_beg, param_end - param_beg ) );
54
}
55
}
56
}
57
58
return result;
59
}
60
61
static bool is_param_exist( const std::vector<std::string> & params, const std::string & param )
62
{
63
if ( params.size() < 2U )
64
return false;
65
66
return std::find(params.begin(), params.end(), param) != params.end();
67
}
68
69
//===========================================================================================
70
71
CV_IMPL CvFileStorage*
72
cvOpenFileStorage( const char* query, CvMemStorage* dststorage, int flags, const char* encoding )
73
{
74
CvFileStorage* fs = 0;
75
int default_block_size = 1 << 18;
76
bool append = (flags & 3) == CV_STORAGE_APPEND;
77
bool mem = (flags & CV_STORAGE_MEMORY) != 0;
78
bool write_mode = (flags & 3) != 0;
79
bool write_base64 = (write_mode || append) && (flags & CV_STORAGE_BASE64) != 0;
80
bool isGZ = false;
81
size_t fnamelen = 0;
82
const char * filename = query;
83
84
std::vector<std::string> params;
85
if ( !mem )
86
{
87
params = analyze_file_name( query );
88
if ( !params.empty() )
89
filename = params.begin()->c_str();
90
91
if ( write_base64 == false && is_param_exist( params, "base64" ) )
92
write_base64 = (write_mode || append);
93
}
94
95
if( !filename || filename[0] == '\0' )
96
{
97
if( !write_mode )
98
CV_Error( CV_StsNullPtr, mem ? "NULL or empty filename" : "NULL or empty buffer" );
99
mem = true;
100
}
101
else
102
fnamelen = strlen(filename);
103
104
if( mem && append )
105
CV_Error( CV_StsBadFlag, "CV_STORAGE_APPEND and CV_STORAGE_MEMORY are not currently compatible" );
106
107
fs = (CvFileStorage*)cvAlloc( sizeof(*fs) );
108
CV_Assert(fs);
109
memset( fs, 0, sizeof(*fs));
110
111
fs->memstorage = cvCreateMemStorage( default_block_size );
112
fs->dststorage = dststorage ? dststorage : fs->memstorage;
113
114
fs->flags = CV_FILE_STORAGE;
115
fs->write_mode = write_mode;
116
117
if( !mem )
118
{
119
fs->filename = (char*)cvMemStorageAlloc( fs->memstorage, fnamelen+1 );
120
strcpy( fs->filename, filename );
121
122
char* dot_pos = strrchr(fs->filename, '.');
123
char compression = '\0';
124
125
if( dot_pos && dot_pos[1] == 'g' && dot_pos[2] == 'z' &&
126
(dot_pos[3] == '\0' || (cv_isdigit(dot_pos[3]) && dot_pos[4] == '\0')) )
127
{
128
if( append )
129
{
130
cvReleaseFileStorage( &fs );
131
CV_Error(CV_StsNotImplemented, "Appending data to compressed file is not implemented" );
132
}
133
isGZ = true;
134
compression = dot_pos[3];
135
if( compression )
136
dot_pos[3] = '\0', fnamelen--;
137
}
138
139
if( !isGZ )
140
{
141
fs->file = fopen(fs->filename, !fs->write_mode ? "rt" : !append ? "wt" : "a+t" );
142
if( !fs->file )
143
goto _exit_;
144
}
145
else
146
{
147
#if USE_ZLIB
148
char mode[] = { fs->write_mode ? 'w' : 'r', 'b', compression ? compression : '3', '\0' };
149
fs->gzfile = gzopen(fs->filename, mode);
150
if( !fs->gzfile )
151
goto _exit_;
152
#else
153
cvReleaseFileStorage( &fs );
154
CV_Error(CV_StsNotImplemented, "There is no compressed file storage support in this configuration");
155
#endif
156
}
157
}
158
159
fs->roots = 0;
160
fs->struct_indent = 0;
161
fs->struct_flags = 0;
162
fs->wrap_margin = 71;
163
164
if( fs->write_mode )
165
{
166
int fmt = flags & CV_STORAGE_FORMAT_MASK;
167
168
if( mem )
169
fs->outbuf = new std::deque<char>;
170
171
if( fmt == CV_STORAGE_FORMAT_AUTO && filename )
172
{
173
const char* dot_pos = NULL;
174
const char* dot_pos2 = NULL;
175
// like strrchr() implementation, but save two last positions simultaneously
176
for (const char* pos = filename; pos[0] != 0; pos++)
177
{
178
if (pos[0] == '.')
179
{
180
dot_pos2 = dot_pos;
181
dot_pos = pos;
182
}
183
}
184
if (cv_strcasecmp(dot_pos, ".gz") && dot_pos2 != NULL)
185
{
186
dot_pos = dot_pos2;
187
}
188
fs->fmt
189
= (cv_strcasecmp(dot_pos, ".xml") || cv_strcasecmp(dot_pos, ".xml.gz"))
190
? CV_STORAGE_FORMAT_XML
191
: (cv_strcasecmp(dot_pos, ".json") || cv_strcasecmp(dot_pos, ".json.gz"))
192
? CV_STORAGE_FORMAT_JSON
193
: CV_STORAGE_FORMAT_YAML
194
;
195
}
196
else if ( fmt != CV_STORAGE_FORMAT_AUTO )
197
{
198
fs->fmt = fmt;
199
}
200
else
201
{
202
fs->fmt = CV_STORAGE_FORMAT_XML;
203
}
204
205
// we use factor=6 for XML (the longest characters (' and ") are encoded with 6 bytes (' and ")
206
// and factor=4 for YAML ( as we use 4 bytes for non ASCII characters (e.g. \xAB))
207
int buf_size = CV_FS_MAX_LEN*(fs->fmt == CV_STORAGE_FORMAT_XML ? 6 : 4) + 1024;
208
209
if (append)
210
{
211
fseek( fs->file, 0, SEEK_END );
212
if (ftell(fs->file) == 0)
213
append = false;
214
}
215
216
fs->write_stack = cvCreateSeq( 0, sizeof(CvSeq), fs->fmt == CV_STORAGE_FORMAT_XML ?
217
sizeof(CvXMLStackRecord) : sizeof(int), fs->memstorage );
218
fs->is_first = 1;
219
fs->struct_indent = 0;
220
fs->struct_flags = CV_NODE_EMPTY;
221
fs->buffer_start = fs->buffer = (char*)cvAlloc( buf_size + 1024 );
222
fs->buffer_end = fs->buffer_start + buf_size;
223
224
fs->base64_writer = 0;
225
fs->is_default_using_base64 = write_base64;
226
fs->state_of_writing_base64 = base64::fs::Uncertain;
227
228
fs->is_write_struct_delayed = false;
229
fs->delayed_struct_key = 0;
230
fs->delayed_struct_flags = 0;
231
fs->delayed_type_name = 0;
232
233
if( fs->fmt == CV_STORAGE_FORMAT_XML )
234
{
235
size_t file_size = fs->file ? (size_t)ftell( fs->file ) : (size_t)0;
236
fs->strstorage = cvCreateChildMemStorage( fs->memstorage );
237
if( !append || file_size == 0 )
238
{
239
if( encoding )
240
{
241
if( strcmp( encoding, "UTF-16" ) == 0 ||
242
strcmp( encoding, "utf-16" ) == 0 ||
243
strcmp( encoding, "Utf-16" ) == 0 )
244
{
245
cvReleaseFileStorage( &fs );
246
CV_Error( CV_StsBadArg, "UTF-16 XML encoding is not supported! Use 8-bit encoding\n");
247
}
248
249
CV_Assert( strlen(encoding) < 1000 );
250
char buf[1100];
251
sprintf(buf, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding);
252
icvPuts( fs, buf );
253
}
254
else
255
icvPuts( fs, "<?xml version=\"1.0\"?>\n" );
256
icvPuts( fs, "<opencv_storage>\n" );
257
}
258
else
259
{
260
int xml_buf_size = 1 << 10;
261
char substr[] = "</opencv_storage>";
262
int last_occurence = -1;
263
xml_buf_size = MIN(xml_buf_size, int(file_size));
264
fseek( fs->file, -xml_buf_size, SEEK_END );
265
char* xml_buf = (char*)cvAlloc( xml_buf_size+2 );
266
// find the last occurrence of </opencv_storage>
267
for(;;)
268
{
269
int line_offset = (int)ftell( fs->file );
270
char* ptr0 = icvGets( fs, xml_buf, xml_buf_size ), *ptr;
271
if( !ptr0 )
272
break;
273
ptr = ptr0;
274
for(;;)
275
{
276
ptr = strstr( ptr, substr );
277
if( !ptr )
278
break;
279
last_occurence = line_offset + (int)(ptr - ptr0);
280
ptr += strlen(substr);
281
}
282
}
283
cvFree( &xml_buf );
284
if( last_occurence < 0 )
285
{
286
cvReleaseFileStorage( &fs );
287
CV_Error( CV_StsError, "Could not find </opencv_storage> in the end of file.\n" );
288
}
289
icvCloseFile( fs );
290
fs->file = fopen( fs->filename, "r+t" );
291
CV_Assert(fs->file);
292
fseek( fs->file, last_occurence, SEEK_SET );
293
// replace the last "</opencv_storage>" with " <!-- resumed -->", which has the same length
294
icvPuts( fs, " <!-- resumed -->" );
295
fseek( fs->file, 0, SEEK_END );
296
icvPuts( fs, "\n" );
297
}
298
fs->start_write_struct = icvXMLStartWriteStruct;
299
fs->end_write_struct = icvXMLEndWriteStruct;
300
fs->write_int = icvXMLWriteInt;
301
fs->write_real = icvXMLWriteReal;
302
fs->write_string = icvXMLWriteString;
303
fs->write_comment = icvXMLWriteComment;
304
fs->start_next_stream = icvXMLStartNextStream;
305
}
306
else if( fs->fmt == CV_STORAGE_FORMAT_YAML )
307
{
308
if( !append)
309
icvPuts( fs, "%YAML:1.0\n---\n" );
310
else
311
icvPuts( fs, "...\n---\n" );
312
fs->start_write_struct = icvYMLStartWriteStruct;
313
fs->end_write_struct = icvYMLEndWriteStruct;
314
fs->write_int = icvYMLWriteInt;
315
fs->write_real = icvYMLWriteReal;
316
fs->write_string = icvYMLWriteString;
317
fs->write_comment = icvYMLWriteComment;
318
fs->start_next_stream = icvYMLStartNextStream;
319
}
320
else
321
{
322
if( !append )
323
icvPuts( fs, "{\n" );
324
else
325
{
326
bool valid = false;
327
long roffset = 0;
328
for ( ;
329
fseek( fs->file, roffset, SEEK_END ) == 0;
330
roffset -= 1 )
331
{
332
const char end_mark = '}';
333
if ( fgetc( fs->file ) == end_mark )
334
{
335
fseek( fs->file, roffset, SEEK_END );
336
valid = true;
337
break;
338
}
339
}
340
341
if ( valid )
342
{
343
icvCloseFile( fs );
344
fs->file = fopen( fs->filename, "r+t" );
345
CV_Assert(fs->file);
346
fseek( fs->file, roffset, SEEK_END );
347
fputs( ",", fs->file );
348
}
349
else
350
{
351
CV_Error( CV_StsError, "Could not find '}' in the end of file.\n" );
352
}
353
}
354
fs->struct_indent = 4;
355
fs->start_write_struct = icvJSONStartWriteStruct;
356
fs->end_write_struct = icvJSONEndWriteStruct;
357
fs->write_int = icvJSONWriteInt;
358
fs->write_real = icvJSONWriteReal;
359
fs->write_string = icvJSONWriteString;
360
fs->write_comment = icvJSONWriteComment;
361
fs->start_next_stream = icvJSONStartNextStream;
362
}
363
}
364
else
365
{
366
if( mem )
367
{
368
fs->strbuf = filename;
369
fs->strbufsize = fnamelen;
370
}
371
372
size_t buf_size = 1 << 20;
373
const char* yaml_signature = "%YAML";
374
const char* json_signature = "{";
375
const char* xml_signature = "<?xml";
376
char buf[16];
377
icvGets( fs, buf, sizeof(buf)-2 );
378
char* bufPtr = cv_skip_BOM(buf);
379
size_t bufOffset = bufPtr - buf;
380
381
if(strncmp( bufPtr, yaml_signature, strlen(yaml_signature) ) == 0)
382
fs->fmt = CV_STORAGE_FORMAT_YAML;
383
else if(strncmp( bufPtr, json_signature, strlen(json_signature) ) == 0)
384
fs->fmt = CV_STORAGE_FORMAT_JSON;
385
else if(strncmp( bufPtr, xml_signature, strlen(xml_signature) ) == 0)
386
fs->fmt = CV_STORAGE_FORMAT_XML;
387
else if(fs->strbufsize == bufOffset)
388
CV_Error(CV_BADARG_ERR, "Input file is empty");
389
else
390
CV_Error(CV_BADARG_ERR, "Unsupported file storage format");
391
392
if( !isGZ )
393
{
394
if( !mem )
395
{
396
fseek( fs->file, 0, SEEK_END );
397
buf_size = ftell( fs->file );
398
}
399
else
400
buf_size = fs->strbufsize;
401
buf_size = MIN( buf_size, (size_t)(1 << 20) );
402
buf_size = MAX( buf_size, (size_t)(CV_FS_MAX_LEN*2 + 1024) );
403
}
404
icvRewind(fs);
405
fs->strbufpos = bufOffset;
406
407
fs->str_hash = cvCreateMap( 0, sizeof(CvStringHash),
408
sizeof(CvStringHashNode), fs->memstorage, 256 );
409
410
fs->roots = cvCreateSeq( 0, sizeof(CvSeq),
411
sizeof(CvFileNode), fs->memstorage );
412
413
fs->buffer = fs->buffer_start = (char*)cvAlloc( buf_size + 256 );
414
fs->buffer_end = fs->buffer_start + buf_size;
415
fs->buffer[0] = '\n';
416
fs->buffer[1] = '\0';
417
418
//mode = cvGetErrMode();
419
//cvSetErrMode( CV_ErrModeSilent );
420
try
421
{
422
switch (fs->fmt)
423
{
424
case CV_STORAGE_FORMAT_XML : { icvXMLParse ( fs ); break; }
425
case CV_STORAGE_FORMAT_YAML: { icvYMLParse ( fs ); break; }
426
case CV_STORAGE_FORMAT_JSON: { icvJSONParse( fs ); break; }
427
default: break;
428
}
429
}
430
catch (...)
431
{
432
fs->is_opened = true;
433
cvReleaseFileStorage( &fs );
434
CV_RETHROW();
435
}
436
//cvSetErrMode( mode );
437
438
// release resources that we do not need anymore
439
cvFree( &fs->buffer_start );
440
fs->buffer = fs->buffer_end = 0;
441
}
442
fs->is_opened = true;
443
444
_exit_:
445
if( fs )
446
{
447
if( cvGetErrStatus() < 0 || (!fs->file && !fs->gzfile && !fs->outbuf && !fs->strbuf) )
448
{
449
cvReleaseFileStorage( &fs );
450
}
451
else if( !fs->write_mode )
452
{
453
icvCloseFile(fs);
454
// we close the file since it's not needed anymore. But icvCloseFile() resets is_opened,
455
// which may be misleading. Since we restore the value of is_opened.
456
fs->is_opened = true;
457
}
458
}
459
460
return fs;
461
}
462
463
464
/* closes file storage and deallocates buffers */
465
CV_IMPL void
466
cvReleaseFileStorage( CvFileStorage** p_fs )
467
{
468
if( !p_fs )
469
CV_Error( CV_StsNullPtr, "NULL double pointer to file storage" );
470
471
if( *p_fs )
472
{
473
CvFileStorage* fs = *p_fs;
474
*p_fs = 0;
475
476
icvClose(fs, 0);
477
478
cvReleaseMemStorage( &fs->strstorage );
479
cvFree( &fs->buffer_start );
480
cvReleaseMemStorage( &fs->memstorage );
481
482
delete fs->outbuf;
483
delete fs->base64_writer;
484
delete[] fs->delayed_struct_key;
485
delete[] fs->delayed_type_name;
486
487
memset( fs, 0, sizeof(*fs) );
488
cvFree( &fs );
489
}
490
}
491
492
493
CV_IMPL void*
494
cvLoad( const char* filename, CvMemStorage* memstorage,
495
const char* name, const char** _real_name )
496
{
497
void* ptr = 0;
498
const char* real_name = 0;
499
cv::FileStorage fs(cvOpenFileStorage(filename, memstorage, CV_STORAGE_READ));
500
501
CvFileNode* node = 0;
502
503
if( !fs.isOpened() )
504
return 0;
505
506
if( name )
507
{
508
node = cvGetFileNodeByName( *fs, 0, name );
509
}
510
else
511
{
512
int i, k;
513
for( k = 0; k < (*fs)->roots->total; k++ )
514
{
515
CvSeq* seq;
516
CvSeqReader reader;
517
518
node = (CvFileNode*)cvGetSeqElem( (*fs)->roots, k );
519
CV_Assert(node != NULL);
520
if( !CV_NODE_IS_MAP( node->tag ))
521
return 0;
522
seq = node->data.seq;
523
node = 0;
524
525
cvStartReadSeq( seq, &reader, 0 );
526
527
// find the first element in the map
528
for( i = 0; i < seq->total; i++ )
529
{
530
if( CV_IS_SET_ELEM( reader.ptr ))
531
{
532
node = (CvFileNode*)reader.ptr;
533
goto stop_search;
534
}
535
CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
536
}
537
}
538
539
stop_search:
540
;
541
}
542
543
if( !node )
544
CV_Error( CV_StsObjectNotFound, "Could not find the/an object in file storage" );
545
546
real_name = cvGetFileNodeName( node );
547
ptr = cvRead( *fs, node, 0 );
548
549
// sanity check
550
if( !memstorage && (CV_IS_SEQ( ptr ) || CV_IS_SET( ptr )) )
551
CV_Error( CV_StsNullPtr,
552
"NULL memory storage is passed - the loaded dynamic structure can not be stored" );
553
554
if( cvGetErrStatus() < 0 )
555
{
556
cvRelease( (void**)&ptr );
557
real_name = 0;
558
}
559
560
if( _real_name)
561
{
562
if (real_name)
563
{
564
*_real_name = (const char*)cvAlloc(strlen(real_name));
565
memcpy((void*)*_real_name, real_name, strlen(real_name));
566
} else {
567
*_real_name = 0;
568
}
569
}
570
571
return ptr;
572
}
573
574
CV_IMPL const char*
575
cvAttrValue( const CvAttrList* attr, const char* attr_name )
576
{
577
while( attr && attr->attr )
578
{
579
int i;
580
for( i = 0; attr->attr[i*2] != 0; i++ )
581
{
582
if( strcmp( attr_name, attr->attr[i*2] ) == 0 )
583
return attr->attr[i*2+1];
584
}
585
attr = attr->next;
586
}
587
588
return 0;
589
}
590
591
592
#define CV_HASHVAL_SCALE 33
593
594
CV_IMPL CvStringHashNode*
595
cvGetHashedKey( CvFileStorage* fs, const char* str, int len, int create_missing )
596
{
597
CvStringHashNode* node = 0;
598
unsigned hashval = 0;
599
int i, tab_size;
600
601
if( !fs )
602
return 0;
603
604
CvStringHash* map = fs->str_hash;
605
606
if( len < 0 )
607
{
608
for( i = 0; str[i] != '\0'; i++ )
609
hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
610
len = i;
611
}
612
else for( i = 0; i < len; i++ )
613
hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
614
615
hashval &= INT_MAX;
616
tab_size = map->tab_size;
617
if( (tab_size & (tab_size - 1)) == 0 )
618
i = (int)(hashval & (tab_size - 1));
619
else
620
i = (int)(hashval % tab_size);
621
622
for( node = (CvStringHashNode*)(map->table[i]); node != 0; node = node->next )
623
{
624
if( node->hashval == hashval &&
625
node->str.len == len &&
626
memcmp( node->str.ptr, str, len ) == 0 )
627
break;
628
}
629
630
if( !node && create_missing )
631
{
632
node = (CvStringHashNode*)cvSetNew( (CvSet*)map );
633
node->hashval = hashval;
634
node->str = cvMemStorageAllocString( map->storage, str, len );
635
node->next = (CvStringHashNode*)(map->table[i]);
636
map->table[i] = node;
637
}
638
639
return node;
640
}
641
642
CV_IMPL CvFileNode*
643
cvGetFileNode( CvFileStorage* fs, CvFileNode* _map_node,
644
const CvStringHashNode* key,
645
int create_missing )
646
{
647
CvFileNode* value = 0;
648
int k = 0, attempts = 1;
649
650
if( !fs )
651
return 0;
652
653
CV_CHECK_FILE_STORAGE(fs);
654
655
if( !key )
656
CV_Error( CV_StsNullPtr, "Null key element" );
657
658
if( _map_node )
659
{
660
if( !fs->roots )
661
return 0;
662
attempts = fs->roots->total;
663
}
664
665
for( k = 0; k < attempts; k++ )
666
{
667
int i, tab_size;
668
CvFileNode* map_node = _map_node;
669
CvFileMapNode* another;
670
CvFileNodeHash* map;
671
672
if( !map_node )
673
map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
674
CV_Assert(map_node != NULL);
675
if( !CV_NODE_IS_MAP(map_node->tag) )
676
{
677
if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) &&
678
CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE )
679
CV_Error( CV_StsError, "The node is neither a map nor an empty collection" );
680
return 0;
681
}
682
683
map = map_node->data.map;
684
tab_size = map->tab_size;
685
686
if( (tab_size & (tab_size - 1)) == 0 )
687
i = (int)(key->hashval & (tab_size - 1));
688
else
689
i = (int)(key->hashval % tab_size);
690
691
for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next )
692
if( another->key == key )
693
{
694
if( !create_missing )
695
{
696
value = &another->value;
697
return value;
698
}
699
CV_PARSE_ERROR( "Duplicated key" );
700
}
701
702
if( k == attempts - 1 && create_missing )
703
{
704
CvFileMapNode* node = (CvFileMapNode*)cvSetNew( (CvSet*)map );
705
node->key = key;
706
707
node->next = (CvFileMapNode*)(map->table[i]);
708
map->table[i] = node;
709
value = (CvFileNode*)node;
710
}
711
}
712
713
return value;
714
}
715
716
CV_IMPL CvFileNode*
717
cvGetFileNodeByName( const CvFileStorage* fs, const CvFileNode* _map_node, const char* str )
718
{
719
CvFileNode* value = 0;
720
int i, len, tab_size;
721
unsigned hashval = 0;
722
int k = 0, attempts = 1;
723
724
if( !fs )
725
return 0;
726
727
CV_CHECK_FILE_STORAGE(fs);
728
729
if( !str )
730
CV_Error( CV_StsNullPtr, "Null element name" );
731
732
for( i = 0; str[i] != '\0'; i++ )
733
hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
734
hashval &= INT_MAX;
735
len = i;
736
737
if( !_map_node )
738
{
739
if( !fs->roots )
740
return 0;
741
attempts = fs->roots->total;
742
}
743
744
for( k = 0; k < attempts; k++ )
745
{
746
CvFileNodeHash* map;
747
const CvFileNode* map_node = _map_node;
748
CvFileMapNode* another;
749
750
if( !map_node )
751
map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
752
753
if( !CV_NODE_IS_MAP(map_node->tag) )
754
{
755
if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) &&
756
CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE )
757
CV_Error( CV_StsError, "The node is neither a map nor an empty collection" );
758
return 0;
759
}
760
761
map = map_node->data.map;
762
tab_size = map->tab_size;
763
764
if( (tab_size & (tab_size - 1)) == 0 )
765
i = (int)(hashval & (tab_size - 1));
766
else
767
i = (int)(hashval % tab_size);
768
769
for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next )
770
{
771
const CvStringHashNode* key = another->key;
772
773
if( key->hashval == hashval &&
774
key->str.len == len &&
775
memcmp( key->str.ptr, str, len ) == 0 )
776
{
777
value = &another->value;
778
return value;
779
}
780
}
781
}
782
783
return value;
784
}
785
786
CV_IMPL CvFileNode*
787
cvGetRootFileNode( const CvFileStorage* fs, int stream_index )
788
{
789
CV_CHECK_FILE_STORAGE(fs);
790
791
if( !fs->roots || (unsigned)stream_index >= (unsigned)fs->roots->total )
792
return 0;
793
794
return (CvFileNode*)cvGetSeqElem( fs->roots, stream_index );
795
}
796
797
CV_IMPL void
798
cvStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
799
const char* type_name, CvAttrList /*attributes*/ )
800
{
801
CV_CHECK_OUTPUT_FILE_STORAGE(fs);
802
check_if_write_struct_is_delayed( fs );
803
if ( fs->state_of_writing_base64 == base64::fs::NotUse )
804
switch_to_Base64_state( fs, base64::fs::Uncertain );
805
806
if ( fs->state_of_writing_base64 == base64::fs::Uncertain
807
&&
808
CV_NODE_IS_SEQ(struct_flags)
809
&&
810
fs->is_default_using_base64
811
&&
812
type_name == 0
813
)
814
{
815
/* Uncertain whether output Base64 data */
816
make_write_struct_delayed( fs, key, struct_flags, type_name );
817
}
818
else if ( type_name && memcmp(type_name, "binary", 6) == 0 )
819
{
820
/* Must output Base64 data */
821
if ( !CV_NODE_IS_SEQ(struct_flags) )
822
CV_Error( CV_StsBadArg, "must set 'struct_flags |= CV_NODE_SEQ' if using Base64.");
823
else if ( fs->state_of_writing_base64 != base64::fs::Uncertain )
824
CV_Error( CV_StsError, "function \'cvStartWriteStruct\' calls cannot be nested if using Base64.");
825
826
fs->start_write_struct( fs, key, struct_flags, type_name );
827
828
if ( fs->state_of_writing_base64 != base64::fs::Uncertain )
829
switch_to_Base64_state( fs, base64::fs::Uncertain );
830
switch_to_Base64_state( fs, base64::fs::InUse );
831
}
832
else
833
{
834
/* Won't output Base64 data */
835
if ( fs->state_of_writing_base64 == base64::fs::InUse )
836
CV_Error( CV_StsError, "At the end of the output Base64, `cvEndWriteStruct` is needed.");
837
838
fs->start_write_struct( fs, key, struct_flags, type_name );
839
840
if ( fs->state_of_writing_base64 != base64::fs::Uncertain )
841
switch_to_Base64_state( fs, base64::fs::Uncertain );
842
switch_to_Base64_state( fs, base64::fs::NotUse );
843
}
844
}
845
846
847
CV_IMPL void
848
cvEndWriteStruct( CvFileStorage* fs )
849
{
850
CV_CHECK_OUTPUT_FILE_STORAGE(fs);
851
check_if_write_struct_is_delayed( fs );
852
853
if ( fs->state_of_writing_base64 != base64::fs::Uncertain )
854
switch_to_Base64_state( fs, base64::fs::Uncertain );
855
856
fs->end_write_struct( fs );
857
}
858
859
860
CV_IMPL void
861
cvWriteInt( CvFileStorage* fs, const char* key, int value )
862
{
863
CV_CHECK_OUTPUT_FILE_STORAGE(fs);
864
fs->write_int( fs, key, value );
865
}
866
867
868
CV_IMPL void
869
cvWriteReal( CvFileStorage* fs, const char* key, double value )
870
{
871
CV_CHECK_OUTPUT_FILE_STORAGE(fs);
872
fs->write_real( fs, key, value );
873
}
874
875
876
CV_IMPL void
877
cvWriteString( CvFileStorage* fs, const char* key, const char* value, int quote )
878
{
879
CV_CHECK_OUTPUT_FILE_STORAGE(fs);
880
fs->write_string( fs, key, value, quote );
881
}
882
883
884
CV_IMPL void
885
cvWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
886
{
887
CV_CHECK_OUTPUT_FILE_STORAGE(fs);
888
fs->write_comment( fs, comment, eol_comment );
889
}
890
891
892
CV_IMPL void
893
cvStartNextStream( CvFileStorage* fs )
894
{
895
CV_CHECK_OUTPUT_FILE_STORAGE(fs);
896
fs->start_next_stream( fs );
897
}
898
899
CV_IMPL void
900
cvWriteRawData( CvFileStorage* fs, const void* _data, int len, const char* dt )
901
{
902
if (fs->is_default_using_base64 ||
903
fs->state_of_writing_base64 == base64::fs::InUse )
904
{
905
cvWriteRawDataBase64( fs, _data, len, dt );
906
return;
907
}
908
else if ( fs->state_of_writing_base64 == base64::fs::Uncertain )
909
{
910
switch_to_Base64_state( fs, base64::fs::NotUse );
911
}
912
913
const char* data0 = (const char*)_data;
914
int offset = 0;
915
int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k, fmt_pair_count;
916
char buf[256] = "";
917
918
CV_CHECK_OUTPUT_FILE_STORAGE( fs );
919
920
if( len < 0 )
921
CV_Error( CV_StsOutOfRange, "Negative number of elements" );
922
923
fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
924
925
if( !len )
926
return;
927
928
if( !data0 )
929
CV_Error( CV_StsNullPtr, "Null data pointer" );
930
931
if( fmt_pair_count == 1 )
932
{
933
fmt_pairs[0] *= len;
934
len = 1;
935
}
936
937
for(;len--;)
938
{
939
for( k = 0; k < fmt_pair_count; k++ )
940
{
941
int i, count = fmt_pairs[k*2];
942
int elem_type = fmt_pairs[k*2+1];
943
int elem_size = CV_ELEM_SIZE(elem_type);
944
const char* data, *ptr;
945
946
offset = cvAlign( offset, elem_size );
947
data = data0 + offset;
948
949
for( i = 0; i < count; i++ )
950
{
951
switch( elem_type )
952
{
953
case CV_8U:
954
ptr = icv_itoa( *(uchar*)data, buf, 10 );
955
data++;
956
break;
957
case CV_8S:
958
ptr = icv_itoa( *(char*)data, buf, 10 );
959
data++;
960
break;
961
case CV_16U:
962
ptr = icv_itoa( *(ushort*)data, buf, 10 );
963
data += sizeof(ushort);
964
break;
965
case CV_16S:
966
ptr = icv_itoa( *(short*)data, buf, 10 );
967
data += sizeof(short);
968
break;
969
case CV_32S:
970
ptr = icv_itoa( *(int*)data, buf, 10 );
971
data += sizeof(int);
972
break;
973
case CV_32F:
974
ptr = icvFloatToString( buf, *(float*)data );
975
data += sizeof(float);
976
break;
977
case CV_64F:
978
ptr = icvDoubleToString( buf, *(double*)data );
979
data += sizeof(double);
980
break;
981
case CV_USRTYPE1: /* reference */
982
ptr = icv_itoa( (int)*(size_t*)data, buf, 10 );
983
data += sizeof(size_t);
984
break;
985
default:
986
CV_Error( CV_StsUnsupportedFormat, "Unsupported type" );
987
return;
988
}
989
990
if( fs->fmt == CV_STORAGE_FORMAT_XML )
991
{
992
int buf_len = (int)strlen(ptr);
993
icvXMLWriteScalar( fs, 0, ptr, buf_len );
994
}
995
else if ( fs->fmt == CV_STORAGE_FORMAT_YAML )
996
{
997
icvYMLWrite( fs, 0, ptr );
998
}
999
else
1000
{