Line data Source code
1 : /* File: io_data_file.c; Copyright and License: see below */
2 :
3 : #include "io_data_file.h"
4 : #include "io_exporter.h"
5 : #include "io_file_format.h"
6 : #include "io_importer.h"
7 : #include "io_import_mode.h"
8 : #include "entity/data_head.h"
9 : #include "entity/data_head_key.h"
10 : #include "storage/data_database_head.h"
11 : #include "u8dir/u8dir_file.h"
12 : #include "u8stream/universal_file_input_stream.h"
13 : #include "u8stream/universal_null_output_stream.h"
14 : #include "u8stream/universal_output_stream.h"
15 : #include "u8/u8_trace.h"
16 : #include "u8/u8_log.h"
17 : #include "u8/u8_u64.h"
18 : #include <assert.h>
19 :
20 : static const char *IO_DATA_FILE_TEMP_EXT = ".tmp-cfu";
21 : static const char *IO_DATA_FILE_JSON_EXT = ".cfuJ";
22 :
23 3 : void io_data_file_init ( io_data_file_t *this_ )
24 : {
25 3 : U8_TRACE_BEGIN();
26 :
27 3 : data_database_init( &((*this_).database) );
28 3 : ctrl_controller_init( &((*this_).controller), &((*this_).database) );
29 :
30 : (*this_).data_file_name
31 3 : = utf8stringbuf_new( (*this_).private_data_file_name_buffer, sizeof((*this_).private_data_file_name_buffer) );
32 3 : utf8stringbuf_clear( &((*this_).data_file_name) );
33 :
34 : (*this_).db_file_name
35 3 : = utf8stringbuf_new( (*this_).private_db_file_name_buffer, sizeof((*this_).private_db_file_name_buffer) );
36 3 : utf8stringbuf_clear( &((*this_).db_file_name) );
37 :
38 3 : (*this_).auto_writeback_to_json = false;
39 3 : (*this_).delete_db_when_finished = false;
40 3 : (*this_).sync_revision = DATA_REVISION_VOID;
41 :
42 3 : U8_TRACE_END();
43 3 : }
44 :
45 3 : void io_data_file_destroy ( io_data_file_t *this_ )
46 : {
47 3 : U8_TRACE_BEGIN();
48 :
49 3 : ctrl_controller_destroy( &((*this_).controller) );
50 3 : data_database_destroy( &((*this_).database) );
51 :
52 3 : U8_TRACE_END();
53 3 : }
54 :
55 4 : u8_error_t io_data_file_open ( io_data_file_t *this_,
56 : const char* requested_file_path,
57 : bool read_only,
58 : u8_error_info_t *out_err_info )
59 : {
60 4 : U8_TRACE_BEGIN();
61 4 : assert( requested_file_path != NULL );
62 4 : assert( out_err_info != NULL );
63 4 : u8_error_info_init_void( out_err_info );
64 4 : const utf8stringview_t req_file_path = UTF8STRINGVIEW_STR(requested_file_path);
65 : utf8stringview_t req_file_parent;
66 : utf8stringview_t req_file_name;
67 : utf8stringview_t req_file_basename;
68 : utf8stringview_t req_file_extension;
69 4 : io_data_file_private_split_path( this_, &req_file_path, &req_file_parent, &req_file_name );
70 4 : io_data_file_private_split_extension( this_, &req_file_name, &req_file_basename, &req_file_extension );
71 :
72 4 : const bool temp_requested = utf8string_ends_with_str( requested_file_path, IO_DATA_FILE_TEMP_EXT );
73 : bool is_json;
74 4 : const u8_error_t file_not_readable = io_data_file_private_guess_db_type( this_, requested_file_path, &is_json );
75 4 : u8_error_t err = U8_ERROR_NONE;
76 :
77 4 : if ( file_not_readable != U8_ERROR_NONE )
78 : {
79 2 : if (( temp_requested )||( ! is_json ))
80 : {
81 0 : U8_LOG_EVENT( "rejecting to create a new database based on a given tmp-cfu filename..." );
82 0 : U8_TRACE_INFO( "CASE: use temp db file that does not exist, is not accessible or has wrong format" );
83 : /* This request happens when the user selected the .tmp-fcu file of an already open database. */
84 : /* When the database has been closed, the .tmp-cfu file vanishes and now cannot be found anymore. */
85 0 : (*this_).auto_writeback_to_json = false;
86 0 : (*this_).delete_db_when_finished = false;
87 :
88 0 : err |= utf8stringbuf_copy_view( &((*this_).data_file_name), &req_file_parent );
89 0 : err |= utf8stringbuf_append_view( &((*this_).data_file_name), &req_file_basename );
90 0 : err |= utf8stringbuf_append_str( &((*this_).data_file_name), IO_DATA_FILE_JSON_EXT );
91 :
92 0 : err |= utf8stringbuf_copy_str( &((*this_).db_file_name), requested_file_path );
93 :
94 0 : U8_TRACE_INFO_STR( "data_file_name:", utf8stringbuf_get_string( &((*this_).data_file_name) ) );
95 0 : U8_TRACE_INFO_STR( "db_file_name: ", utf8stringbuf_get_string( &((*this_).db_file_name) ) );
96 :
97 : /* do not open a non-existing .tmp-cfu file */
98 0 : err = U8_ERROR_FILE_ALREADY_REMOVED;
99 :
100 : /* new file is not in sync by definition */
101 0 : (*this_).sync_revision = DATA_REVISION_VOID;
102 : }
103 : else
104 : {
105 2 : U8_LOG_EVENT( "creating a new database based on a given json filename (cfuJ)..." );
106 2 : U8_TRACE_INFO( "CASE: use json file that does not exist or is not accessible" );
107 : /* A new json file shall be created */
108 2 : (*this_).auto_writeback_to_json = true;
109 2 : (*this_).delete_db_when_finished = true;
110 2 : err |= utf8stringbuf_copy_str( &((*this_).data_file_name), requested_file_path );
111 :
112 2 : err |= utf8stringbuf_copy_view( &((*this_).db_file_name), &req_file_parent );
113 2 : err |= utf8stringbuf_append_view( &((*this_).db_file_name), &req_file_basename );
114 2 : err |= utf8stringbuf_append_str( &((*this_).db_file_name), IO_DATA_FILE_TEMP_EXT );
115 2 : u8dir_file_remove( utf8stringbuf_get_string( &((*this_).db_file_name) ) ); /* ignore possible errors */
116 :
117 2 : U8_TRACE_INFO_STR( "data_file_name:", utf8stringbuf_get_string( &((*this_).data_file_name) ) );
118 2 : U8_TRACE_INFO_STR( "db_file_name: ", utf8stringbuf_get_string( &((*this_).db_file_name) ) );
119 :
120 2 : err |= data_database_open( &((*this_).database), utf8stringbuf_get_string( &((*this_).db_file_name) ) );
121 :
122 : /* new file is not in sync by definition */
123 2 : (*this_).sync_revision = DATA_REVISION_VOID;
124 : }
125 : }
126 : else
127 : {
128 2 : if ( temp_requested )
129 : {
130 0 : U8_LOG_EVENT( "opening an existing database based on a given tmp-cfu filename..." );
131 0 : U8_TRACE_INFO( "CASE: use existing temp file" );
132 : /* A temporary sqlite file shall be used and later be exported to json */
133 0 : (*this_).auto_writeback_to_json = true;
134 0 : (*this_).delete_db_when_finished = true;
135 0 : err |= utf8stringbuf_copy_view( &((*this_).data_file_name), &req_file_parent );
136 0 : err |= utf8stringbuf_append_view( &((*this_).data_file_name), &req_file_basename );
137 0 : err |= utf8stringbuf_append_str( &((*this_).data_file_name), IO_DATA_FILE_JSON_EXT );
138 :
139 0 : err |= utf8stringbuf_copy_str( &((*this_).db_file_name), requested_file_path );
140 :
141 0 : U8_TRACE_INFO_STR( "data_file_name:", utf8stringbuf_get_string( &((*this_).data_file_name) ) );
142 0 : U8_TRACE_INFO_STR( "db_file_name: ", utf8stringbuf_get_string( &((*this_).db_file_name) ) );
143 :
144 0 : err |= data_database_open( &((*this_).database), utf8stringbuf_get_string( &((*this_).db_file_name) ) );
145 :
146 : /* temp file is not in sync by definition */
147 0 : (*this_).sync_revision = DATA_REVISION_VOID;
148 :
149 : /* Reading the DATA_HEAD_KEY_DATA_FILE_NAME from the just opened (*this_).db_file_name */
150 : /* If found, update (*this_).data_file_name */
151 0 : if ( err == U8_ERROR_NONE )
152 : {
153 : data_database_head_t head_table;
154 0 : data_database_head_init( &head_table, &((*this_).database) );
155 :
156 : data_head_t head;
157 0 : u8_error_t key_err = data_database_head_read_value_by_key( &head_table, DATA_HEAD_KEY_DATA_FILE_NAME, &head );
158 0 : if ( key_err == U8_ERROR_NONE )
159 : {
160 : /* case: recovery after abnormal program termination */
161 0 : U8_TRACE_INFO_STR( "data_file_name (updated):", data_head_get_value_const( &head ) );
162 : /* set the data_file_name to the read head value */
163 0 : err |= utf8stringbuf_copy_view( &((*this_).data_file_name), &req_file_parent );
164 0 : err |= utf8stringbuf_append_str( &((*this_).data_file_name), data_head_get_value_const( &head ) );
165 : }
166 :
167 0 : data_database_head_destroy( &head_table );
168 : }
169 : }
170 2 : else if ( is_json )
171 : {
172 2 : U8_LOG_EVENT( "opening an existing database based on a given json filename (cfuJ)..." );
173 2 : U8_TRACE_INFO_STR( "CASE: use existing json file ", read_only ? "read_only" : "writeable" );
174 : /* An existing json file shall be used */
175 2 : (*this_).auto_writeback_to_json = ( ! read_only );
176 2 : (*this_).delete_db_when_finished = true;
177 2 : err |= utf8stringbuf_copy_str( &((*this_).data_file_name), requested_file_path );
178 :
179 2 : err |= utf8stringbuf_copy_view( &((*this_).db_file_name), &req_file_parent );
180 2 : err |= utf8stringbuf_append_view( &((*this_).db_file_name), &req_file_basename );
181 2 : err |= utf8stringbuf_append_str( &((*this_).db_file_name), IO_DATA_FILE_TEMP_EXT );
182 2 : u8dir_file_remove( utf8stringbuf_get_string( &((*this_).db_file_name) ) ); /* ignore possible errors */
183 :
184 2 : U8_TRACE_INFO_STR( "data_file_name:", utf8stringbuf_get_string( &((*this_).data_file_name) ) );
185 2 : U8_TRACE_INFO_STR( "db_file_name: ", utf8stringbuf_get_string( &((*this_).db_file_name) ) );
186 :
187 2 : err |= data_database_open( &((*this_).database), utf8stringbuf_get_string( &((*this_).db_file_name) ) );
188 2 : if ( err != U8_ERROR_NONE )
189 : {
190 0 : U8_LOG_ERROR("An error occurred at creating a temporary database file, possibly the parent directory is read-only.")
191 0 : U8_LOG_WARNING("Changes will not be written back to not accidentally overwrite the data source")
192 0 : (*this_).auto_writeback_to_json = false;
193 0 : (*this_).delete_db_when_finished = true; /* do not keep .tmp-cfu file, it was not successfully created anyhow */
194 :
195 : /* temp file is not in sync because import not possible */
196 0 : (*this_).sync_revision = DATA_REVISION_VOID;
197 : }
198 : else
199 : {
200 : /* import */
201 2 : err |= io_data_file_private_import( this_, utf8stringbuf_get_string( &((*this_).data_file_name) ), out_err_info );
202 :
203 2 : if ( err != U8_ERROR_NONE )
204 : {
205 1 : err |= data_database_close( &((*this_).database) );
206 :
207 1 : U8_LOG_ERROR("An error occurred at reading a json data file")
208 1 : u8dir_file_remove( utf8stringbuf_get_string( &((*this_).db_file_name) ) ); /* ignore possible additional errors */
209 1 : U8_LOG_WARNING("Changes will not be written back to not accidentally overwrite the data source")
210 1 : (*this_).auto_writeback_to_json = false;
211 1 : (*this_).delete_db_when_finished = false; /* .tmp-cfu file was just deleted */
212 : /* file is not in sync with closed db */
213 1 : (*this_).sync_revision = DATA_REVISION_VOID;
214 : }
215 : else
216 : {
217 1 : (*this_).sync_revision = data_database_get_revision( &((*this_).database) );
218 1 : U8_TRACE_INFO_INT( "sync_revision", (*this_).sync_revision );
219 :
220 : /* update head data */
221 : data_database_head_t head_table;
222 1 : data_database_head_init( &head_table, &((*this_).database) );
223 : {
224 : /* DATA_HEAD_KEY_DATA_FILE_NAME */
225 : data_head_t head1;
226 1 : const char *const requested_file_name = utf8stringview_get_start( &req_file_name ); /* This view is null terminated */
227 1 : data_head_init_new( &head1, DATA_HEAD_KEY_DATA_FILE_NAME, requested_file_name );
228 1 : err |= data_database_head_create_value( &head_table, &head1, NULL );
229 1 : data_head_destroy( &head1 );
230 1 : U8_TRACE_INFO_STR( "io_data_file_open/DATA_FILE_NAME", requested_file_name );
231 :
232 : /* DATA_HEAD_KEY_DATA_FILE_LAST_SYNC_MOD_TIME */
233 : uint64_t mod_time;
234 1 : u8_error_t mtime_err = u8dir_file_get_modification_time( requested_file_path, &mod_time );
235 1 : if ( mtime_err == U8_ERROR_NONE )
236 : {
237 : u8_u64_hex_t hex_time;
238 1 : u8_u64_get_hex( mod_time, &hex_time );
239 : data_head_t head2;
240 1 : data_head_init_new( &head2, DATA_HEAD_KEY_DATA_FILE_LAST_SYNC_MOD_TIME, &(hex_time[0]) );
241 1 : err |= data_database_head_create_value( &head_table, &head2, NULL );
242 1 : data_head_destroy( &head2 );
243 1 : U8_TRACE_INFO_STR( "io_data_file_open/DATA_FILE_LAST_SYNC_MOD_TIME", &(hex_time[0]) );
244 : }
245 : }
246 1 : data_database_head_destroy( &head_table );
247 :
248 : /* restore revision to the one that is stored in the undo redo list */
249 1 : data_database_set_revision( &((*this_).database), (*this_).sync_revision );
250 : }
251 : }
252 : }
253 : else
254 : {
255 0 : U8_LOG_EVENT( "opening an existing database based on an old sqlite3 filename (cfu1)..." );
256 0 : U8_TRACE_INFO( "CASE: use existing sqlite file, auto-convert it to json" );
257 : /* An old sqlite file shall be used, this is automatically converted to json */
258 0 : (*this_).auto_writeback_to_json = true;
259 0 : (*this_).delete_db_when_finished = true;
260 0 : err |= utf8stringbuf_copy_view( &((*this_).data_file_name), &req_file_parent );
261 0 : err |= utf8stringbuf_append_view( &((*this_).data_file_name), &req_file_basename );
262 0 : err |= utf8stringbuf_append_str( &((*this_).data_file_name), IO_DATA_FILE_JSON_EXT );
263 :
264 0 : err |= utf8stringbuf_copy_str( &((*this_).db_file_name), requested_file_path );
265 :
266 0 : U8_TRACE_INFO_STR( "data_file_name:", utf8stringbuf_get_string( &((*this_).data_file_name) ) );
267 0 : U8_TRACE_INFO_STR( "db_file_name: ", utf8stringbuf_get_string( &((*this_).db_file_name) ) );
268 :
269 0 : err |= data_database_open( &((*this_).database), utf8stringbuf_get_string( &((*this_).db_file_name) ) );
270 :
271 : /* old file is not in sync to force conversion to json */
272 0 : (*this_).sync_revision = DATA_REVISION_VOID;
273 : }
274 : }
275 :
276 4 : U8_TRACE_END_ERR( err );
277 4 : return err;
278 : }
279 :
280 2 : u8_error_t io_data_file_close ( io_data_file_t *this_ )
281 : {
282 2 : U8_TRACE_BEGIN();
283 :
284 2 : u8_error_t result = U8_ERROR_NONE;
285 :
286 2 : if ( (*this_).auto_writeback_to_json && ( ! io_data_file_is_in_sync( this_ ) ) )
287 : {
288 2 : U8_TRACE_INFO( "CASE: auto_writeback_to_json == true" );
289 2 : result |= io_data_file_private_export( this_, utf8stringbuf_get_string( &((*this_).data_file_name) ) );
290 : }
291 :
292 2 : result |= data_database_close( &((*this_).database) );
293 :
294 2 : if ( (*this_).delete_db_when_finished )
295 : {
296 2 : U8_TRACE_INFO( "CASE: delete_db_when_finished == true" );
297 2 : u8dir_file_remove( utf8stringbuf_get_string( &((*this_).db_file_name) ) ); /* ignore possible errors */
298 : }
299 :
300 2 : (*this_).auto_writeback_to_json = false;
301 2 : (*this_).delete_db_when_finished = false;
302 :
303 2 : U8_TRACE_END_ERR( result );
304 2 : return result;
305 : }
306 :
307 0 : u8_error_t io_data_file_sync_to_disk ( io_data_file_t *this_ )
308 : {
309 0 : U8_TRACE_BEGIN();
310 :
311 0 : u8_error_t result = data_database_flush_caches( &((*this_).database) );
312 :
313 0 : if ( (*this_).auto_writeback_to_json ) /* ignore if already in_sync - if explicitly requested, simply do sync (again) */
314 : {
315 0 : result |= io_data_file_private_export( this_, utf8stringbuf_get_string( &((*this_).data_file_name) ) );
316 : }
317 :
318 : /* get sync revision */
319 0 : (*this_).sync_revision = data_database_get_revision( &((*this_).database) );
320 0 : U8_TRACE_INFO_INT( "sync_revision", (*this_).sync_revision );
321 :
322 : /* update head data */
323 : data_database_head_t head_table;
324 0 : data_database_head_init( &head_table, &((*this_).database) );
325 : {
326 : /* DATA_HEAD_KEY_DATA_FILE_LAST_SYNC_MOD_TIME */
327 : uint64_t mod_time;
328 0 : const char *const json_file_path = utf8stringbuf_get_string( &((*this_).data_file_name) );
329 0 : u8_error_t mtime_err = u8dir_file_get_modification_time( json_file_path, &mod_time );
330 0 : if ( mtime_err == U8_ERROR_NONE )
331 : {
332 : u8_u64_hex_t hex_time;
333 0 : u8_u64_get_hex( mod_time, &hex_time );
334 0 : result |= data_database_head_update_value_by_key( &head_table,
335 : DATA_HEAD_KEY_DATA_FILE_LAST_SYNC_MOD_TIME,
336 : &(hex_time[0]),
337 : true,
338 : NULL
339 : );
340 0 : U8_TRACE_INFO_STR( "io_data_file_sync_to_disk/DATA_FILE_LAST_SYNC_MOD_TIME", &(hex_time[0]) );
341 : }
342 : }
343 0 : data_database_head_destroy( &head_table );
344 :
345 : /* restore sync revision so that undo_redo history and this_ refer to the same revision */
346 0 : data_database_set_revision( &((*this_).database), (*this_).sync_revision );
347 :
348 0 : U8_TRACE_END_ERR( result );
349 0 : return result;
350 : }
351 :
352 0 : bool io_data_file_is_externally_modified ( io_data_file_t *this_ )
353 : {
354 0 : U8_TRACE_BEGIN();
355 0 : bool result = false;
356 :
357 0 : if ( data_database_is_open( &((*this_).database) ) )
358 : {
359 : data_database_head_t head_table;
360 0 : data_database_head_init( &head_table, &((*this_).database) );
361 : {
362 : uint64_t mod_time;
363 0 : const char *const json_file_path = utf8stringbuf_get_string( &((*this_).data_file_name) );
364 0 : u8_error_t mtime_err = u8dir_file_get_modification_time( json_file_path, &mod_time );
365 0 : if ( mtime_err == U8_ERROR_NONE )
366 : {
367 : u8_u64_hex_t hex_time;
368 0 : u8_u64_get_hex( mod_time, &hex_time );
369 :
370 : data_head_t head_val;
371 : const u8_error_t db_err
372 0 : = data_database_head_read_value_by_key( &head_table,
373 : DATA_HEAD_KEY_DATA_FILE_LAST_SYNC_MOD_TIME,
374 : &head_val
375 : );
376 0 : if ( db_err == U8_ERROR_NONE )
377 : {
378 0 : if ( ! utf8string_equals_str( &(hex_time[0]), data_head_get_value_const( &head_val ) ) )
379 : {
380 0 : result = true;
381 : }
382 : }
383 : }
384 : }
385 0 : data_database_head_destroy( &head_table );
386 : }
387 :
388 0 : U8_TRACE_END();
389 0 : return result;
390 : }
391 :
392 0 : u8_error_t io_data_file_trace_stats ( io_data_file_t *this_ )
393 : {
394 0 : U8_TRACE_BEGIN();
395 :
396 0 : U8_TRACE_INFO_STR( "io_data_file_t:", utf8stringbuf_get_string( &((*this_).data_file_name) ) );
397 :
398 0 : const u8_error_t result = data_database_trace_stats( &((*this_).database) );
399 :
400 0 : U8_TRACE_END_ERR( result );
401 0 : return result;
402 : }
403 :
404 4 : u8_error_t io_data_file_private_guess_db_type ( const io_data_file_t *this_, const char *filename, bool *out_json )
405 : {
406 4 : U8_TRACE_BEGIN();
407 4 : assert( filename != NULL );
408 4 : assert( out_json != NULL );
409 4 : u8_error_t scan_head_error = U8_ERROR_NONE;
410 :
411 : /* open file */
412 : universal_file_input_stream_t in_file;
413 4 : universal_file_input_stream_init( &in_file );
414 4 : scan_head_error |= universal_file_input_stream_open( &in_file, filename );
415 :
416 : /* import from stream */
417 4 : if ( scan_head_error == U8_ERROR_NONE )
418 : {
419 : char file_prefix[16];
420 : size_t prefix_size;
421 : assert( sizeof(file_prefix) == sizeof(DATA_DATABASE_SQLITE3_MAGIC) );
422 2 : scan_head_error = universal_file_input_stream_read( &in_file, &file_prefix, sizeof(file_prefix), &prefix_size );
423 2 : if (( scan_head_error == U8_ERROR_NONE )&&( prefix_size == sizeof(file_prefix) )
424 2 : &&( 0 == memcmp( &file_prefix, &DATA_DATABASE_SQLITE3_MAGIC, sizeof(file_prefix) ) ))
425 : {
426 0 : U8_TRACE_INFO_STR("File exists and starts with sqlite3 magic:", filename);
427 0 : *out_json = false;
428 : }
429 : else
430 : {
431 2 : U8_TRACE_INFO_STR("File exists and is not of type sqlite3:", filename);
432 2 : *out_json = true;
433 : }
434 :
435 : /* close file */
436 2 : scan_head_error |= universal_file_input_stream_close( &in_file );
437 : }
438 : else
439 : {
440 2 : U8_TRACE_INFO_STR("File does not exist", filename);
441 2 : *out_json = true;
442 : }
443 :
444 : /* cleanup */
445 4 : scan_head_error |= universal_file_input_stream_destroy( &in_file );
446 :
447 4 : U8_TRACE_END_ERR( scan_head_error );
448 4 : return scan_head_error;
449 : }
450 :
451 2 : u8_error_t io_data_file_private_import ( io_data_file_t *this_, const char *src_file, u8_error_info_t *out_err_info )
452 : {
453 2 : U8_TRACE_BEGIN();
454 2 : assert( src_file != NULL );
455 2 : assert( out_err_info != NULL );
456 2 : u8_error_info_init_void( out_err_info );
457 2 : u8_error_t import_err = U8_ERROR_NONE;
458 : static const io_import_mode_t import_mode = IO_IMPORT_MODE_CREATE|IO_IMPORT_MODE_LINK;
459 : universal_null_output_stream_t dev_null;
460 2 : universal_null_output_stream_init( &dev_null );
461 : utf8stream_writer_t out_null;
462 2 : utf8stream_writer_init( &out_null, universal_null_output_stream_get_output_stream( &dev_null ) );
463 :
464 2 : U8_TRACE_INFO_STR( "importing file:", src_file );
465 2 : if ( io_data_file_is_open( this_ ) )
466 : {
467 : static data_database_reader_t db_reader;
468 2 : data_database_reader_init( &db_reader, &((*this_).database) );
469 : static io_importer_t importer;
470 2 : io_importer_init( &importer, &db_reader, &((*this_).controller) );
471 : {
472 : data_stat_t import_stat;
473 2 : data_stat_init ( &import_stat );
474 2 : import_err = io_importer_import_file( &importer, import_mode, src_file, &import_stat, out_err_info, &out_null );
475 2 : data_stat_trace( &import_stat );
476 2 : data_stat_destroy ( &import_stat );
477 : }
478 2 : io_importer_destroy( &importer );
479 2 : data_database_reader_destroy( &db_reader );
480 : }
481 : else
482 : {
483 0 : import_err = U8_ERROR_NO_DB;
484 : }
485 :
486 2 : utf8stream_writer_destroy( &out_null );
487 2 : universal_null_output_stream_destroy( &dev_null );
488 2 : U8_TRACE_END_ERR( import_err );
489 2 : return import_err;
490 : }
491 :
492 2 : u8_error_t io_data_file_private_export ( io_data_file_t *this_, const char *dst_file )
493 : {
494 2 : U8_TRACE_BEGIN();
495 2 : assert( dst_file != NULL );
496 2 : u8_error_t export_err = U8_ERROR_NONE;
497 :
498 2 : U8_TRACE_INFO_STR( "exporting file:", dst_file );
499 2 : const char *document_filename = io_data_file_get_filename_const( this_ );
500 2 : if ( io_data_file_is_open( this_ ) )
501 : {
502 : static data_database_reader_t db_reader;
503 2 : data_database_reader_init( &db_reader, &((*this_).database) );
504 : static io_exporter_t exporter;
505 2 : io_exporter_init( &exporter, &db_reader );
506 : {
507 : data_stat_t export_stat;
508 2 : data_stat_init ( &export_stat );
509 2 : export_err = io_exporter_export_document_file( &exporter, IO_FILE_FORMAT_JSON, "title", document_filename, &export_stat );
510 2 : data_stat_trace( &export_stat );
511 2 : data_stat_destroy ( &export_stat );
512 : }
513 2 : io_exporter_destroy( &exporter );
514 2 : data_database_reader_destroy( &db_reader );
515 : }
516 : else
517 : {
518 0 : export_err = U8_ERROR_NO_DB;
519 : }
520 :
521 2 : U8_TRACE_END_ERR( export_err );
522 2 : return export_err;
523 : }
524 :
525 :
526 : /*
527 : Copyright 2022-2025 Andreas Warnke
528 :
529 : Licensed under the Apache License, Version 2.0 (the "License");
530 : you may not use this file except in compliance with the License.
531 : You may obtain a copy of the License at
532 :
533 : http://www.apache.org/licenses/LICENSE-2.0
534 :
535 : Unless required by applicable law or agreed to in writing, software
536 : distributed under the License is distributed on an "AS IS" BASIS,
537 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
538 : See the License for the specific language governing permissions and
539 : limitations under the License.
540 : */
|