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